Skip to content

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:

ex:MyBusinessActor am:serves ex:SomeProcess .

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 metamodels
  • realizes — 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:domainIncludes and schema:rangeIncludes as 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 into rdfs:domain/rdfs:range using owl:unionOf — but explicitly warns that the mapping is approximate and non-authoritative.
  • Dublin Core (DCMI) — newer properties avoid rdfs:domain/rdfs:range to 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:range sparingly 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 source or target IS a qualified relationship by definition.
  • The inference is always correct — if something uses arch:source, it should be typed as arch: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:

  1. Load model data (RDF triples)
  2. Load ontology (class hierarchy, property declarations)
  3. Optionally materialize rdfs:subClassOf entailment (for polymorphic shape targeting)
  4. Run SHACL validation against the shapes
  5. 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:rangeIncludes annotations 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:

  1. Use rdfs:domain/rdfs:range only for mono-typed infrastructure properties — structural properties like arch:source/arch:target that live inside one ontology's closed world and where the inference is always correct.

  2. Use arch:domainIncludes/arch:rangeIncludes for any property intended for reuse — especially relationship vocabulary shared across metamodels or used in cross-domain integration.

  3. 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).

  4. Use SKOS for controlled vocabularies — enumerations, classifications, layered taxonomies. Don't model these as OWL classes just because you can.

  5. If you need OWL DL reasoning over relationships, keep a separate "axioms bridge" file with strict rdfs:domain/rdfs:range declarations (using owl:unionOf where 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.

  6. 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 inference
    

    This prevents downstream confusion about what a reasoner will and won't do with the ontology.

  7. Document the choice on the ontology resource itself — in skos:scopeNote or dc: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