In OWL, class hierarchies are fundamental. A Customer that is a subclass of Organization inherits all of Organization's properties — website and foundedYear. You define each property once on the superclass, and every subclass gets it automatically through reasoning.
Customer
Organization
website
foundedYear
SHACL doesn't work this way. Each shape is self-contained. If CustomerShape doesn't explicitly list website as a property, then SHACL will not validate (or in closed mode, will actively reject) website on Customer instances.
CustomerShape
This creates a mismatch:
OWL world: Organization ├── website ← defined on Organization └── foundedYear ← defined on Organization Customer (subClassOf Organization) ├── (inherits website, foundedYear) └── customerID ← own property SHACL world (WITHOUT flattening): OrganizationShape ├── website ✓ └── foundedYear ✓ CustomerShape └── customerID ✓ ⊘ website not listed — validation fails or rejects it!
RDF Studio's OWL-to-SHACL translator solves this by flattening inherited properties — copying every property from superclass shapes down to subclass shapes.
After flattening:
SHACL world (WITH flattening): OrganizationShape ├── website └── foundedYear CustomerShape ├── customerID ← own property ├── website ← flattened from Organization └── foundedYear ← flattened from Organization
Now CustomerShape validates all the properties that a Customer instance actually has — both its own and its inherited ones.
The Northwind ontology demonstrates this perfectly. Organization is a superclass with shared properties, and three subclasses specialize it:
# Organization defines shared properties nwo:Organization a owl:Class . nwo:website a owl:DatatypeProperty ; rdfs:domain nwo:Organization ; rdfs:range xsd:anyURI . nwo:foundedYear a owl:DatatypeProperty ; rdfs:domain nwo:Organization ; rdfs:range xsd:gYear . # Three subclasses nwo:Customer a owl:Class ; rdfs:subClassOf nwo:Organization . nwo:Supplier a owl:Class ; rdfs:subClassOf nwo:Organization . nwo:Shipper a owl:Class ; rdfs:subClassOf nwo:Organization .
OrganizationShape
SupplierShape
ShipperShape
A customer may carry website (it inherits it from Organization via OWL), but CustomerShape doesn't list it → a closed shape reports it as an undeclared property. (The shipped Northwind data has no website or foundedYear values; add one to a customer to see this.)
Now every shape has a complete picture of its instances' expected properties.
The algorithm walks the class hierarchy bottom-up:
rdfs:subClassOf
sh:datatype
sh:minCount
sh:class
Flattening works across multiple levels. If you had:
Thing └── Organization (foundedYear, website) └── Customer (customerID) └── PremiumCustomer (loyaltyTier)
Then PremiumCustomerShape would contain: loyaltyTier (own) + customerID (from Customer) + foundedYear, website (from Organization).
PremiumCustomerShape
loyaltyTier
customerID
The Northwind ontology uses two different patterns for sharing properties across classes:
nwo:companyName a owl:DatatypeProperty ; rdfs:domain [ owl:unionOf (nwo:Customer nwo:Shipper nwo:Supplier) ] ; rdfs:range xsd:string .
Here, companyName is directly assigned to three classes via owl:unionOf. No inheritance involved — the translator places a property shape on each listed class. This is explicit and clear.
companyName
owl:unionOf
nwo:website a owl:DatatypeProperty ; rdfs:domain nwo:Organization ; rdfs:range xsd:anyURI . nwo:Customer rdfs:subClassOf nwo:Organization .
Here, website belongs to Organization, and Customer gets it through inheritance. The translator must flatten it onto CustomerShape.
Both are valid OWL modeling approaches:
The Northwind ontology uses both — contactName and phone use union domains, while website and foundedYear use inheritance through Organization. RDF Studio's translator handles both patterns correctly.
contactName
phone
After generating shapes in RDF Studio, you can verify flattening worked by: