Property Typing: domainIncludes / rangeIncludes vs rdfs:domain / rdfs:range¶
A guide to how Linked.Archi handles property typing — the semantics of rdfs:domain/rdfs:range, why architecture metamodels need a different approach, and how the three-layer pattern (OWL inference, annotation guidance, SHACL validation) works in practice.
For the concise design decision, see DD-6.
How rdfs:domain and rdfs:range actually work¶
The RDFS properties rdfs:domain and rdfs:range are inference axioms, not constraints. The distinction between open-world and closed-world semantics is well understood in the semantic web community, but it has specific consequences for enterprise architecture knowledge graphs that are worth spelling out:
# This does NOT mean "serves can only originate from ApplicationService"
# It means "anything that uses serves IS an ApplicationService"
am:serves rdfs:domain am:ApplicationService .
Given:
A reasoner will not reject this. It will infer ex:MyBusinessActor rdf:type am:ApplicationService — adding a type assertion based purely on property usage.
This is the Open World Assumption at work. The reasoner assumes data is incomplete and fills in what must logically be true given the axioms. There is no concept of "constraint violation" in OWL — only new inferences.
Why architecture metamodels need something different¶
ArchiMate has 11 relationship types, each with a complex validity matrix. The serves relationship alone can originate from dozens of element types. The full matrix has 10,484 valid source/target pairs.
Three characteristics of this domain make rdfs:domain/rdfs:range a poor fit:
1. Multiple domains mean intersection, not union¶
# This means "anything using serves is BOTH an ApplicationService AND a BusinessService"
am:serves rdfs:domain am:ApplicationService .
am:serves rdfs:domain am:BusinessService .
RDFS semantics define multiple rdfs:domain statements as conjunction (AND), not disjunction (OR). To express "ApplicationService OR BusinessService" you'd need owl:unionOf — which pushes into OWL Full and breaks most tooling.
2. Inference instead of validation¶
You never get an error. You get type assertions propagating through the knowledge graph. A BusinessActor that uses serves silently becomes typed as every class listed in the domain. Downstream SHACL shapes fire on it incorrectly, SPARQL queries return unexpected results, and the issue is invisible until someone notices inconsistent data.
3. Pair-wise constraints cannot be expressed¶
ArchiMate's relationship validity is not "property X goes from type A to type B." It's a matrix: "Composition can go from BusinessActor to BusinessRole, from ApplicationComponent to DataObject, from Node to Device, ..." — hundreds of valid pairs per relationship type. rdfs:domain/rdfs:range can only say "all sources are X" and "all targets are Y" independently — it has no mechanism for pair-wise constraints.
The three-layer approach¶
Linked.Archi separates property typing into three layers, each with a different semantic commitment:
┌─────────────────────────────────────────────────────────────────┐
│ Layer 3: SHACL Shapes — Closed-world VALIDATION │
│ "This relationship instance MUST have source of type X │
│ and target of type Y — reject if not" │
├─────────────────────────────────────────────────────────────────┤
│ Layer 2: arch:domainIncludes / arch:rangeIncludes — GUIDANCE │
│ "This property is typically used with these types — │
│ suggest them in tooling, document them for humans" │
├─────────────────────────────────────────────────────────────────┤
│ Layer 1: rdfs:subClassOf hierarchy — INFERENCE │
│ "This element IS-A ActiveStructureElement — │
│ shapes targeting ActiveStructureElement apply to it" │
└─────────────────────────────────────────────────────────────────┘
Layer 1: Class hierarchy (inference)¶
am:BusinessActor rdfs:subClassOf am:InternalActiveStructureElement .
am:InternalActiveStructureElement rdfs:subClassOf am:ActiveStructureElement .
A reasoner infers that BusinessActor instances are also ActiveStructureElement instances. SHACL shapes use rdf:type/rdfs:subClassOf* property paths to apply rules polymorphically ("assignment can only originate from ActiveStructureElements").
Layer 2: Annotation properties (guidance)¶
arch:domainIncludes
a owl:AnnotationProperty ;
skos:definition "defines classes for the subject of a Relationship. It is not to be used for validation" ;
skos:closeMatch schema:domainIncludes .
am:serves
a owl:ObjectProperty ;
arch:domainIncludes arch:Element ;
arch:rangeIncludes arch:Element .
arch:domainIncludes is typed as owl:AnnotationProperty. Reasoners ignore annotation properties — they produce zero inferences. The values serve as machine-readable documentation that modeling tools can query to populate connection wizards, auto-complete dialogs, and palette filters.
Layer 3: SHACL shapes (validation)¶
:ServingShape
a sh:NodeShape ;
sh:targetClass am:Serving ;
sh:or (
[ sh:and (
[ sh:property [ sh:path arch:source ; sh:class am:ApplicationService ] ]
[ sh:property [ sh:path arch:target ; sh:class am:BusinessProcess ] ]
) ]
[ sh:and (
[ sh:property [ sh:path arch:source ; sh:class am:ApplicationService ] ]
[ sh:property [ sh:path arch:target ; sh:class am:BusinessFunction ] ]
) ]
# ... hundreds more valid pairs
) .
SHACL operates under the Closed World Assumption. If a relationship instance doesn't match any listed valid pair, it produces a validation report with the violation.
How the layers interact¶
SHACL validates whatever graph it receives. If RDFS entailment runs before SHACL (as in GraphDB, Stardog, or any triplestore with reasoning enabled), materialized inferences become part of the validated graph.
| Entailment type | Effect on SHACL | Desired? |
|---|---|---|
rdfs:subClassOf transitivity |
Shapes targeting am:ActiveStructureElement fire on am:BusinessActor instances |
Yes — polymorphic validation |
rdfs:domain/rdfs:range inference |
Shapes targeting am:Node fire on anything that uses a property with rdfs:domain am:Node |
No — pollutes the type graph |
Keeping rdfs:domain/rdfs:range off relationship properties means the type graph stays clean. Only explicit rdf:type assertions and rdfs:subClassOf inheritance determine which shapes apply to which instances.
The trade-off¶
| Capability | With rdfs:domain/rdfs:range |
With arch:domainIncludes/arch:rangeIncludes |
|---|---|---|
| RDFS entailment of subject/object types | Yes — automatic | No |
| OWL DL consistency checks based on declared types | Yes | No |
| Polymorphic reuse across modules | Awkward (intersection trap) | Natural |
| Closed-world validation messages | No (Open World Assumption) | Yes, via SHACL |
| Class explosion via "union container" classes | Often required | Avoided |
| Surprising inferences on imported data | Common | Rare |
| Handling incomplete/untyped data | Invents types (often wrong) | Leaves untyped (surfaces as validation finding) |
The exchange: implicit reasoner-driven type assignment from property use is traded for predictability, polymorphism, and clean composition. SHACL validation provides what you'd want from rdfs:domain (catching wrong usages) without the inferential side effects.
Cross-metamodel composition¶
Linked.Archi spans ArchiMate, C4, BPMN, UML, Backstage, LeanIX, TOGAF, and custom metamodels. Several relationship names recur across these languages with overlapping but non-identical type expectations:
serves— used in ArchiMate (services serving processes), Backstage (APIs serving components), custom metamodelsrealizes— used in ArchiMate (components realizing services), UML (classes realizing interfaces)composedOf— used across nearly every modeling language
With rdfs:domain/rdfs:range, adding a new metamodel that reuses an existing property would retroactively affect all other metamodels importing the same property. The intersection semantics would force artificial union classes purely as vocabulary plumbing.
With arch:domainIncludes/arch:rangeIncludes, a property can carry multiple declarations from different metamodel modules without those declarations entailing anything about each other. Adding a Cloud Platform metamodel that extends the core does not affect existing ArchiMate or Backstage assets. This is the polymorphic, descriptive approach that a multi-language vocabulary needs.
Handling incomplete and loosely-typed data¶
Enterprise architecture data comes from diverse sources: ArchiMate tool exports, Backstage YAML catalogs, ServiceNow CMDB pulls, LeanIX API dumps, Terraform state files, and manual spreadsheets. These sources often don't declare types reliably — an imported node might say :app1 am:serves :process1 without explicitly typing either resource.
With rdfs:domain/rdfs:range, the reasoner invents types for untyped resources based on which properties they use. The inferred types may be wrong, they propagate to downstream shapes and queries, and the issue is invisible until someone notices inconsistent results.
With arch:domainIncludes/arch:rangeIncludes, untyped data stays untyped. SHACL validation reports "missing type" or "invalid source/target pair" as an actionable finding — surfacing problems rather than papering over them with potentially incorrect inferences.
What inference remains¶
The domainIncludes/rangeIncludes approach does not eliminate inference — it scopes it to where it produces correct results:
OWL/RDFS reasoner provides:
✓ Class hierarchy (rdfs:subClassOf transitivity)
✓ Subproperty hierarchy (rdfs:subPropertyOf)
✓ Safe structural typing (rdfs:domain/range on infrastructure properties)
✓ Inverse properties where declared
✓ Transitive properties where declared (partOf/hasPart)
SHACL validator provides:
✓ Allowed relationship source/target combinations
✓ Required properties and cardinalities
✓ Metamodel conformance
✓ Viewpoint conformance
✓ Data quality constraints
SHACL/SPARQL rules provide:
✓ Derived relationships (DR1–DR8, PDR1–PDR12)
✓ Materialized analysis results
✓ Confidence/provenance-tagged inferred facts
This separation — monotonic semantic entailment vs closed-world conformance checking vs rule-based derivation — keeps each mechanism doing what it does well.
Ontology formality¶
The semantics of the Linked.Archi ontologies are split across layers:
| Layer | Role |
|---|---|
| OWL/RDFS classes and properties | Vocabulary, hierarchy, structural semantics, safe entailments |
arch:domainIncludes / arch:rangeIncludes |
Intended modeling applicability, documentation, UI/tooling hints |
| SHACL shapes | Conformance checking and relationship validity |
| SHACL rules / SPARQL rules | Derivation and materialized inference |
| SKOS | Taxonomy, classification, navigation |
Each layer uses W3C-standard formats with model-theoretic semantics. A rdfs:subClassOf chain is just as formal here as anywhere. SHACL has its own formal semantics. SKOS too.
The ontologies are valid OWL 2 DL — no metaclass patterns, no punning, no OWL Full constructs. Standard reasoners (HermiT, Pellet, ELK) can process them. The class hierarchy carries real inference. owl:imports provides genuine modular composition.
What the metamodels do not use is OWL's expressive constructs (property restrictions, equivalent classes, disjointness, complex class expressions) for defining relationship constraints. They lean on OWL for taxonomy and on SHACL for constraints. This makes them "lightweight" or "schema-style" ontologies — closer in spirit to Schema.org, FIBO's lighter modules, or DCAT than to DOLCE, BFO, or Cyc.
The characterization: Linked.Archi ontologies are formal ontologies plus validation/rule assets. domainIncludes/rangeIncludes are intentional, non-entailing metamodel annotations. Conformance is delegated to SHACL.
Precedent: Schema.org and other large vocabularies¶
This pattern is used by several major vocabularies:
- Schema.org — defines
schema:domainIncludesandschema:rangeIncludesas the primary mechanism for property typing. The most widely deployed structured data vocabulary on the web. It publishes an experimental OWL bridge that converts these intordfs:domain/rdfs:rangeusingowl:unionOf— but explicitly warns that the mapping is approximate and non-authoritative. - Dublin Core (DCMI) — newer properties avoid
rdfs:domain/rdfs:rangeto prevent unintended inference in mixed-vocabulary graphs. DCMI describes domain/range includes as helping users understand intended usage rather than producing logical inference. - PROV-O — uses qualified patterns (similar to Linked.Archi's qualified relationships) and avoids strict domain/range on many properties to support cross-domain provenance.
- DCAT — the W3C Data Catalog Vocabulary uses
rdfs:domain/rdfs:rangesparingly and relies on SHACL application profiles for validation.
The common thread: vocabularies designed for use in heterogeneous environments tend to avoid rdfs:domain/rdfs:range on properties that cross type boundaries or get reused across modules.
The skos:closeMatch design¶
Linked.Archi defines its own arch:domainIncludes and arch:rangeIncludes rather than reusing schema:domainIncludes directly. The two are linked via skos:closeMatch — not owl:equivalentProperty or rdfs:subPropertyOf. This says "similar to the Schema.org pattern" without committing consumers to Schema.org's exact interpretation or importing the Schema.org namespace as a dependency.
When rdfs:domain / rdfs:range is used¶
Linked.Archi does use rdfs:domain/rdfs:range where the inference is structurally correct:
arch:hasQualifiedRelationship
a owl:ObjectProperty ;
rdfs:domain arch:ModelConcept ;
rdfs:range arch:QualifiedRelationship .
arch:source
a owl:ObjectProperty ;
rdfs:domain arch:QualifiedRelationship ;
rdfs:range arch:ModelConcept .
arch:target
a owl:ObjectProperty ;
rdfs:domain arch:QualifiedRelationship ;
rdfs:range arch:ModelConcept .
am:accessType
a owl:DatatypeProperty ;
rdfs:domain am:Access ;
rdfs:range xsd:string .
These are appropriate because:
- The properties are structurally bound to these types — anything that has a
sourceortargetIS a qualified relationship by definition. - The inference is always correct — if something uses
arch:source, it should be typed asarch:QualifiedRelationship. - There's no many-to-many matrix — simple one-to-one structural relationships.
- These are infrastructure properties within a single ontology's closed world, not user-extensible vocabulary shared across metamodels.
The rule of thumb: use rdfs:domain/rdfs:range when the inference is a tautology (the type assertion is always correct) and the property is mono-typed within a single module. Use arch:domainIncludes/arch:rangeIncludes when the property is used across multiple types, across multiple metamodels, or when the inference would be wrong for some usages.
Practical implications¶
For SPARQL queries¶
Without rdfs:domain/rdfs:range, SPARQL queries under RDFS entailment won't auto-filter by property type. Explicit type checks are needed:
# Returns all triples regardless of source/target type:
SELECT ?source ?target WHERE {
?source am:serves ?target .
}
# With explicit type check:
SELECT ?source ?target WHERE {
?source a/rdfs:subClassOf* am:BehaviorElement .
?source am:serves ?target .
}
The query author decides what types to filter on, rather than the reasoner adding type assertions that may be wrong.
For modeling tools¶
Tools query arch:domainIncludes/arch:rangeIncludes to populate connection wizards:
# "What types can be the source of a Serving relationship?"
SELECT ?sourceType WHERE {
am:serves arch:domainIncludes ?sourceType .
}
This returns guidance for the UI without affecting the inference graph. The tool suggests valid connections; the SHACL shapes enforce them.
For validation pipelines¶
The validation pipeline:
- Load model data (RDF triples)
- Load ontology (class hierarchy, property declarations)
- Optionally materialize
rdfs:subClassOfentailment (for polymorphic shape targeting) - Run SHACL validation against the shapes
- Report violations
Step 3 is safe because rdfs:subClassOf entailment only adds correct type assertions. If rdfs:domain/rdfs:range were present on relationship properties, step 3 would also add incorrect type assertions, corrupting the validation results.
For interoperability¶
Tools that expect rdfs:domain/rdfs:range (some older ontology editors, some visualization tools) won't find them on relationship properties. In practice:
- Modern tools (Protégé 5.x, TopBraid, PoolParty) understand annotation properties
- The SHACL shapes provide the actual constraint information
- The
arch:domainIncludes/arch:rangeIncludesannotations are queryable by any SPARQL-capable tool
For adopters: practical advice¶
If you're building your own metamodel on Linked.Archi or adopting this pattern elsewhere:
-
Use
rdfs:domain/rdfs:rangeonly for mono-typed infrastructure properties — structural properties likearch:source/arch:targetthat live inside one ontology's closed world and where the inference is always correct. -
Use
arch:domainIncludes/arch:rangeIncludesfor any property intended for reuse — especially relationship vocabulary shared across metamodels or used in cross-domain integration. -
Put real constraints in SHACL. Tag shapes with
sh:severity(sh:Violation,sh:Warning,sh:Info) so governance can dial enforcement up or down depending on context (draft models vs production baselines). -
Use SKOS for controlled vocabularies — enumerations, classifications, layered taxonomies. Don't model these as OWL classes just because you can.
-
If you need OWL DL reasoning over relationships, keep a separate "axioms bridge" file with strict
rdfs:domain/rdfs:rangedeclarations (usingowl:unionOfwhere needed) and load it only when you need that reasoning regime. Don't bake it into the shareable metamodel. Schema.org does something similar — it publishes an OWL conversion but warns it's approximate and non-authoritative. -
Document the reasoning profile in your metamodel manifest:
Canonical semantics: OWL/RDFS: vocabulary, hierarchy, structural entailment arch:domainIncludes / arch:rangeIncludes: non-entailing modeling guidance SHACL: validation/conformance SHACL rules/SPARQL: derivation/materialized inferenceThis prevents downstream confusion about what a reasoner will and won't do with the ontology.
-
Document the choice on the ontology resource itself — in
skos:scopeNoteordc:description— so consumers know what to expect from a reasoner without reading external documentation.
Summary¶
| Question | Answer |
|---|---|
| What are these ontologies? | Valid OWL 2 DL with real inference via class hierarchies, plus SHACL for validation |
| Can reasoners process them? | Yes — class hierarchy inference works normally |
Why no rdfs:domain/rdfs:range on relationships? |
The inference produces incorrect type assertions in a many-to-many domain |
| Where do constraints live? | In SHACL shapes — closed-world validation |
What do arch:domainIncludes/arch:rangeIncludes do? |
Machine-readable guidance for tooling without triggering inference |
| Is this approach standard? | Yes — same pattern as Schema.org, Dublin Core, and other large-scale vocabularies |
When is rdfs:domain/rdfs:range appropriate? |
When the inference is always correct (structural properties with a single valid type) |
References¶
- DD-6: domainIncludes / rangeIncludes — The design decision
- Architecture & Approach — Overall technical architecture
- Relationship Modeling Guide — The three-declaration pattern
- Validation Guide — How SHACL validation works in practice
- Schema.org: domainIncludes — The Schema.org precedent
- Schema.org: Developers — OWL bridge discussion
- DCMI: Domain Includes and Range Includes — Dublin Core's approach
- RDF Schema 1.1 — W3C (defines rdfs:domain/range semantics)
- SHACL Specification — W3C Shapes Constraint Language
- OWL 2 Structural Specification — W3C (annotation properties are nonlogical)
- OWL 2 Web Ontology Language — W3C
- RDF 1.2 Semantics — RDFS entailment rules