This is the fourth issue in the series on why Enterprise Architecture practice could use a fundamentally different information system model. This post is about extensibility: how ArchiMate’s specialization mechanism translates into the RDF model,
What the Specification Actually Says
Section 4.5 of the ArchiMate 3.2 specification defines two language customization mechanisms: profiling and specialization. Profiling allows properties and attributes to be added to existing element and relationship types. Specialization allows new types to be derived from existing ones by refining their definition — a specialized element inherits all properties of its parent type, can be used anywhere the parent type is valid, and must conform to the same relationship rules.
The specification is explicit about what specialization means structurally: a specialized element is its parent type. Not a reference to it. Not a wrapper around it. A Person that specializes BusinessActor is a BusinessActor. Every relationship rule that applies to BusinessActor applies to Person. Every query written against BusinessActor returns Person instances. Every SHACL shape targeting BusinessActor fires on Person. The inheritance is complete and unconditional.
This is the mechanism. The question is what it takes to implement it faithfully in RDF, and the answer requires not one declaration but three.
The Three-Declaration Pattern
Every profile class in the ontology makes three simultaneous claims. Here is Person, the simplest example:
myModel:Person rdf:type owl:Class ; rdfs:subClassOf archimate:BusinessActor ; archimate:specialization archimate:BusinessActor ; rdfs:label "Person" ; rdfs:comment "A BusinessActor representing an individual person." .
Three declarations. Each one does a different job. All three are required.
rdfs:subClassOf archimate:BusinessActor is the OWL declaration. It tells a reasoner that every instance of Person is also an instance of BusinessActor. This is what makes queries work without modification: a SPARQL query asking ?x rdf:type archimate:BusinessActor returns Person instances through rdfs:subClassOf* inference. A SHACL shape targeting archimate:BusinessActor fires on Person instances because the reasoner has already classified them as BusinessActor. The triple inheritance pattern from Post 2 — where a BusinessActor is simultaneously a BusinessLayer element, an ActiveStructure element, and a Concept — extends to Person automatically, through the subclass chain, without any additional declarations.
archimate:specialization archimate:BusinessActor is the derivation rule hook. As established in Post 3, archimate:specialization is declared as an owl:TransitiveProperty. This is what makes Person → BusinessActor → Element inferrable as a chain rather than requiring each step to be asserted separately. More importantly, the PDR rules (Potential Derivation Rules PDR1–PDR4) use archimate:specialization as the mechanism by which specialized elements participate in relationship derivations. A Person assigned to a BusinessRole can derive the same relationship chains that BusinessActor derives — not because the derivation rules were rewritten for Person, but because Person participates in the specialization property graph that the rules traverse.
Without this declaration, Person would be a subclass in the OWL hierarchy but invisible to the SHACL-AF derivation engine. The relationship derivations that made Posts 3 valuable — the ones that materialize inferred connections across layers — would silently fail for specialized element instances.
The sh:NodeShape on the same URI (defined in validation/archimate_validation_profiles.ttl) is the validation contract:
myModel:Person sh:NodeShape ; rdfs:label "Person" ; sh:property [ sh:path archimate:name ; sh:datatype xsd:string ; sh:minCount 1 ; sh:order 1 ] ; sh:property [ sh:path myModel:dateOfBirth ; sh:datatype xsd:date ; sh:order 2 ] ; sh:property [ sh:path myModel:email ; sh:datatype xsd:anyURI ; sh:order 3 ] .
The same URI — archimate-prof:Person — is simultaneously an owl:Class and an sh:NodeShape. This is legal and deliberate. The class side drives inference. The shape side drives validation. A SHACL processor targeting Person instances finds the shape through the implicit class-target pattern: because the shape URI matches the class URI, instances of the class are automatically the shape’s target. No separate sh:targetClass declaration needed. The domain-specific properties — dateOfBirth, email — attach to the governed model, not to a separate metadata layer or a properties spreadsheet.
The separation matters for the same reason the three-file structure matters: a reasoner consuming archimate.ttl does not need to load the profile shapes. A governance tool running SHACL validation does not need to understand OWL inference. Each layer is independently consumable by the tooling that needs it.
Nesting Works for Free
The three-declaration pattern composes. An Employee that specializes Person needs only three more declarations:
myModel:Employee rdf:type owl:Class ; rdfs:subClassOf myModel:Person ; archimate:specialization myModel:Person ; rdfs:label "Employee" .
What this buys without any additional work:
Through rdfs:subClassOf transitivity, Employee is simultaneously a Person, a BusinessActor, an ActiveStructure, a BusinessLayer element, and a Concept. The full triple inheritance chain from Post 2, six levels deep, inherited automatically. A query against archimate:BusinessActor returns Employee instances. A SHACL shape targeting archimate:ActiveStructure fires on Employee instances.
Through archimate:specialization transitivity (declared as owl:TransitiveProperty), Employee specializes both Person and BusinessActor. The derivation engine sees the full chain — Employee → Person → BusinessActor — and applies PDR rules accordingly.
The Person SHACL shape fires on Employee instances through the subclass chain: because Employee is a subclass of Person, and Person has a shape, the shape’s property constraints apply to Employee. The Employee-specific shape can add additional constraints without duplicating the ones inherited from Person.
The profile adds domain-specific knowledge — Employee might carry hireDate, employeeId — without touching the core ontology, without modifying the SHACL validation levels from Post 3, and without forking the derivation rules. The extension mechanism is additive by construction.
Full Taxonomies: How Deep Can You Go?
The three-declaration pattern is not limited to one or two levels. It composes to arbitrary depth. A full HR taxonomy is a legitimate use of the mechanism:
archimate:BusinessActor ├── myModel:Person │ ├── myModel:Employee │ │ ├── myModel:FullTimeEmployee │ │ └── myModel:Contractor │ └── myModel:ExternalContact └── myModel:Organization
Every leaf class gets the full inheritance stack automatically. A FullTimeEmployee instance is simultaneously a FullTimeEmployee, an Employee, a Person, a BusinessActor, an ActiveStructure, a BusinessLayer element, and a Concept — through rdfs:subClassOf transitivity, without a single additional assertion. A SPARQL query against archimate:BusinessActor returns instances at every level of the taxonomy. The derivation engine sees the full specialization chain at every level because archimate:specialization is owl:TransitiveProperty. The Exchange Format adapter walks up the rdfs:subClassOf chain regardless of depth — FullTimeEmployee resolves to BusinessActor in five steps, not two, but the recursive walk handles it identically.
One operational concern worth stating plainly: SHACL shape inheritance is additive but not automatically cumulative in all processors. If you load only the Employee shape without the Person shape, the name and email constraints defined on Person will not fire on Employee instances. The full constraint stack requires the full profile file stack to be loaded. This is not a modeling limitation — it is a deployment concern. Governance tooling that consumes profile shapes needs to load them as a set, not selectively. The shapes are designed to be layered; they need to be consumed that way.
The Differentiation Principle
A taxonomy this deep raises a discipline question that the tooling cannot answer for you: when does a subclass earn its place?
There is a school of thought in ontology engineering — sometimes called the differentiation principle — that a subclass is only valid if it introduces at least one property or constraint that its parent does not have. A FullTimeEmployee that carries no properties beyond Employee is not a subclass. It is a label. Labels belong in SKOS, not OWL.
This principle is enforceable in the stack. At the SHACL level, you can require that every profile shape introduces at least one sh:property with sh:minCount 1 on a path not defined by the parent shape — making the presence of a distinguishing property a hard validation constraint, not a modeling convention. At the OWL level, you can use existential restrictions (owl:someValuesFrom) to assert that class membership requires the existence of a specific property value, giving a reasoner the formal basis to reject instances that carry the class type without the distinguishing property.
The stricter version — enforcing this at Level 1 validation, as a constraint on the ontology’s own profile structure rather than on instance data — would flag any specialization class that does not introduce differentiated constraints. That would make “subclasses must add something new” a first-class rule of the governed platform, not just good practice.
Whether to enforce it at the instance level, the schema level, or both is an architectural decision. But the machinery is there. The ontology does not force the discipline on you. It makes the discipline enforceable if you choose it.
The Concrete Example: One Instance, Three Facts
Let me provide an example to make it all easier to reason when there is a real instance behind them. Here is one:

# Individual instancesmyModel:AlbertoMendoza rdf:type myModel:Person ; archimate:name "Alberto D. Mendoza" ; myModel:email "alberto.d.mendoza@gmail.com"^^xsd:anyURI .myModel:OneITConsultingLLC rdf:type myModel:Organization ; archimate:name "ONE IT Consulting, LLC" .myModel:ITConsultantRole rdf:type archimate:BusinessRole ; archimate:name "IT Consultant" .# Alberto holds the Role via Assignment<< myModel:AlbertoMendoza archimate:assignment myModel:ITConsultantRole >> myModel:startDate "2026-01-01"^^xsd:date ; myModel:contractType "Principal" .# The Org defines the Role via Assignment<< myModel:OneITConsultingLLC archimate:assignment myModel:ITConsultantRole >> myModel:status "Active" .
This shape says that a myModel:Organization‘s aggregation targets must be instances of myModel:Person. Not just any BusinessActor — specifically Person instances. The SHACL validator will reject an Organization that aggregates a Department or a Committee, even though those are also valid BusinessActor specializations.
This is structural governance at the profile level. The core ontology permits BusinessActor aggregation BusinessActor — that is the specification’s rule, and it is correct. The profile layer narrows that permission for a specific organizational context, without modifying the core and without requiring that narrowing to apply universally.
This is the extensibility story in one shape: the core ontology defines what is structurally valid across all ArchiMate models. Profile shapes define what is contextually required within a specific domain. The two layers operate independently. Tooling that only loads the core ontology sees a valid ArchiMate model. Tooling that also loads the profile shapes sees a model with domain-specific constraints enforced. The governance tightens as you load more of the stack — without breaking the floor.
Profile Validation
The ArchiMate Ontology validation files (to be described in the next post) operate on standard ArchiMate element types and at different levels. Profile shapes is the a fourth validation level which operates on specialized types while remaining compatible with the three levels above it.
The profile validation file (archimate_validation_profile_examples.ttl) defines shapes for myModel:Person and myModel:Organization. Here is what the actual file contains:
myModel:Person sh:NodeShape ; rdfs:label "Person" ; sh:property [ sh:path myModel:firstName ; sh:name "First Name" ; sh:datatype xsd:string ; sh:minCount 1 ; sh:order 1 ] ; sh:property [ sh:path myModel:lastName ; sh:name "Last Name" ; sh:datatype xsd:string ; sh:minCount 1 ; sh:order 2 ] ; sh:property [ sh:path myModel:dateOfBirth ; sh:name "Date of Birth" ; sh:datatype xsd:date ; sh:order 3 ] ; sh:property [ sh:path myModel:email ; sh:name "Email" ; sh:datatype xsd:anyURI ; sh:order 4 ] .myModel:Organization sh:NodeShape ; rdfs:label "Organization" ; sh:property [ sh:path archimate:aggregation ; sh:name "Members" ; sh:class myModel:Person ; sh:order 1 ] .
Three things worth noting about this file.
archimate:name and archimate:documentation are not declared here. Level 1 already enforces archimate:name with sh:minCount 1 on every realized archimate:Concept. Redeclaring it in the profile shape would be redundant — and more importantly, it would obscure the differentiation principle. A profile shape should contain only what distinguishes that profile from a generic BusinessActor. myModel:firstName and myModel:lastName with sh:minCount 1 are the distinguishing constraints. A BusinessActor without a first name is valid. A myModel:Person without one is not. That asymmetry is the point.
The implicit class-target pattern. There is no sh:targetClass declaration in either shape. The shape URI myModel:Person matches the class URI defined in archimate_profile_examples.ttl. SHACL processors recognize this pattern and automatically target instances of the class. The profile class is simultaneously an OWL class, a derivation rule participant, and a SHACL shape target — three roles, one URI.
The loading order matters. The profile shapes must be loaded alongside the full validation stack, not in isolation. If you load only archimate_validation_profiles.ttl without archimate_validation_core.ttl, the archimate:name requirement won’t fire on Person instances. The four levels are designed to compose; they need to be consumed that way. The file header makes this explicit:
# This validation file should be used alongside:# - archimate_validation_core.ttl (Level 1)# - archimate_validation_metamodel.ttl (Level 2)# - archimate_validation_relationships.ttl (Level 3)# - archimate_validation_profiles.ttl (Level 4)# - archimate_derivation_rules.ttl
A model that passes all four levels is conformant with the ArchiMate 3.2 specification at every level — and additionally conformant with the domain-specific constraints the profile layer adds. The governance tightens as you load more of the stack, without breaking the floor.
The Exchange Format
Profiles create a practical problem that the ontology alone cannot solve: ArchiMate tooling — Archi, BiZZdesign, iServer — speaks the ArchiMate Exchange Format, an XML schema defined by The Open Group. That schema knows about BusinessActor. It does not know about Person or Employee or Organization.
A model containing myModel:Person instances cannot be written to the Exchange Format naively. The XML validator will reject element types it does not recognize. And a model that cannot round-trip through the Exchange Format is stranded in RDF — useful for reasoning and federation, but cut off from the tooling ecosystem where architects actually work.
The solution the adapter implements is to walk the rdfs:subClassOf chain at conversion time. The _resolve_type function in ttl_to_archimate_xml.py:
def _resolve_type(rdf_type: str, g: rdflib.Graph, known_types: dict[str, str], _seen: set[str] | None = None) -> str | None: """Walk rdfs:subClassOf chain to find the nearest known ArchiMate type.""" if rdf_type in known_types: return known_types[rdf_type] if _seen is None: _seen = set() if rdf_type in _seen: return None _seen.add(rdf_type) for parent in g.objects(URIRef(rdf_type), RDFS.subClassOf): result = _resolve_type(str(parent), g, known_types, _seen) if result: return result return None
When the converter encounters a Person instance, it looks up myModel:Person in the known types table — not found. It then follows rdfs:subClassOf to archimate:BusinessActor — found. The element is written to XML as xsi:type="BusinessActor". The Person type is preserved as a standard ArchiMate Exchange Format property:
<!-- Property definition in model header --><propertyDefinitions> <propertyDefinition identifier="specialization" type="string"> <name>specialization</name> </propertyDefinition></propertyDefinitions><!-- The specialized element --><element identifier="actor-001" xsi:type="BusinessActor"> <name xml:lang="en">Alberto D. Mendoza</name> <properties> <property propertyDefinitionRef="specialization"> <value xml:lang="en">Person</value> </property> </properties></element><!-- The specialization relationship --><relationship identifier="rel-spec-001" xsi:type="Specialization" source="actor-001" target="actor-002"/><!-- The profile type as a BusinessActor --><element identifier="actor-002" xsi:type="BusinessActor"> <name xml:lang="en">Person</name></element>
The same walk handles custom relationship predicates through _resolve_predicate, which follows rdfs:subPropertyOf chains to find the nearest known ArchiMate relationship type. A custom archimate-prof:reportsTo that is declared as a subproperty of archimate:association will be written to XML as xsi:type="Association", with the original predicate preserved as a property.
The result is that specialized models round-trip through ArchiMate tooling without special-casing and without any hardcoded lookup table for profile types. The adapter is generic: it works for any profile that follows the three-declaration pattern, whether defined in archimate_profile_examples.ttl or in an organization’s own profile file. The architecture of the profile — not a list of known profiles — is what makes conversion possible.
This is worth stating plainly because it is the technical guarantee that makes profiles practical rather than academic: you can build a governed, reasoned, validated model using specialized element types, and an ArchiMate-compatible tool will import it. The knowledge survives the round trip. The specialization type is preserved as metadata. And when the model comes back into RDF — through the complementary XML-to-TTL converter — the specialization is restored.
The Sample Files
The profile examples in the ontology — Person, Organization — are illustrations of the pattern, not a prescription. The ArchiMate Ontology does not define what Person means or what properties it should carry. The whole point of the specialization mechanism is to give the analyst/architect the opportunity to define what its specialized types mean and what constraints govern them.
The ArchiMate Ontology provides is the infrastructure for that definition to be expressed rigorously. The three-declaration pattern is not an isolated artifact — it is a direct encoding of what the ArchiMate specification says what concept specialization is, realized in RDF. rdfs:subClassOf for inheritance. archimate:specialization for derivation rule participation. sh:NodeShape for domain-specific constraint. Any profile that follows this pattern gets the full reasoning and validation machinery for free.
Organizations deploying this ontology can define their own profiles. An insurance company might specialize BusinessObject into Policy, Claim, Premium. A university might specialize BusinessActor into Student, Faculty, Department. A government agency might specialize ApplicationComponent into LegacySystem, CloudService, SharedPlatform. Each of these profiles is a first-class extension of the ArchiMate language — not a workaround, not a tag, not a custom property bolted onto a generic element. A governed type in a governed model.
Next post: SHACL as the enforcement layer. How the validation levels come together, what it means for a model to pass all four validation levels, and what the contract looks like between the ontology and any conforming model.
The ontology is independent and is not an official publication of The Open Group. ArchiMate® is a registered trademark of The Open Group.







Leave a comment