RDFS Entailment Rules

The 14 RDFS entailment rules — what a 'reasoner' actually computes at this layer, with worked traces and three production case studies.

0/7 done

Entailment, in three rules

Entailment in one sentence

An entailed triple is one that must be true given the triples you already wrote. You didn't type it — but any honest reasoner will list it, because the RDFS rules force it. That's it. Entailment is not magic, not statistics, not inference in the ML sense — it's pure book-keeping over a fixed rule set.

The three rules you'll meet every single day

RuleIf you have……then you also havePlain English
rdfs9c1 rdfs:subClassOf c2 and x rdf:type c1x rdf:type c2An instance of a sub-class is also an instance of the super-class.
rdfs7p1 rdfs:subPropertyOf p2 and s p1 os p2 oA statement using a sub-property is also a statement using the super-property.
rdfs2p rdfs:domain d and s p os rdf:type dIf you use a property, the subject gets typed as the property's domain.
rdfs3p rdfs:range r and s p oo rdf:type rIf you use a property, the object gets typed as the property's range.

There are 14 rules in total (W3C RDF 1.1 Semantics §9.2). The other 10 are almost all about RDF/RDFS plumbing — propagating rdf:type of resources, rdfs:Resource membership, rdfs:Literal typing, etc. You almost never reason about them by hand; the four above carry 95% of the practical weight.

Why it's cheap

RDFS entailment is tractable: polynomial in the size of the graph. Practically every triple store materialises these inferences either at write time (forward chaining — store the closure) or rewrites them at query time (backward chaining — expand each ?x a :Person into its sub-classes).

Analogy 1 — Reading the small print aloud

RDFS entailment is a mortgage closing where the lawyer reads every implied clause out loud, so nothing stays hidden in the small print.

You sign three things: 'I am buying this house', 'this house has a roof', 'every roof is a structure'. The lawyer doesn't invent new facts — they spell out the ones you'd already implicitly agreed to: 'therefore you are buying a structure', 'therefore you own a roof', 'therefore property tax applies to a structure'.

That's exactly what rdfs9, rdfs7 and rdfs2 do — they read out loud the triples your asserted ones already entail. The reason it's cheap (polynomial) is the same reason a closing takes hours, not lifetimes: there are finitely many clauses to enumerate, and each one applies in a single, predictable way.

Analogy 2 — The hospital records system

Think of a hospital's patient record system.

  • A nurse types: Alice rdf:type Cardiologist.
  • The schema already says: Cardiologist rdfs:subClassOf Doctor, Doctor rdfs:subClassOf MedicalStaff, MedicalStaff rdfs:subClassOf Person.
  • The schema also says: treats rdfs:domain Doctor, treats rdfs:range Patient.

Without typing a single extra fact, the system already knows:

  1. Alice is a Doctor (rdfs9).
  2. Alice is MedicalStaff (rdfs9 again).
  3. Alice is a Person (rdfs9, transitively).
  4. The moment someone records Alice treats bob, Bob is automatically a Patient (rdfs3).

Nobody typed those four triples. They are entailed. The query 'list every person on staff' now returns Alice — even though no one ever wrote Alice rdf:type Person. That is what entailment buys you.

Worked example — compute the closure by hand

Worked trace — apply the rules step by step

Take this tiny graph (4 asserted triples):

:Manager  rdfs:subClassOf :Employee .
:Employee rdfs:subClassOf :Person .
:worksFor rdfs:domain     :Employee ;
          rdfs:range      :Organisation .
:alice    a               :Manager ;
          :worksFor       :acme .

We have 4 type/structural triples and 2 facts about Alice. Let's compute the RDFS closure by applying the rules until no new triple appears (a fix-point):

Pass 1

  • rdfs9 on :alice a :Manager + :Manager rdfs:subClassOf :Employee:alice a :Employee(new)
  • rdfs2 on :alice :worksFor :acme + :worksFor rdfs:domain :Employee:alice a :Employee (already derived — duplicate, ignored)
  • rdfs3 on :alice :worksFor :acme + :worksFor rdfs:range :Organisation:acme a :Organisation(new)

Pass 2

  • rdfs9 on the new :alice a :Employee + :Employee rdfs:subClassOf :Person:alice a :Person(new)

Pass 3

Nothing fires that hasn't already fired. Fix-point reached.

Final closure

The reasoner adds 3 new triples to the original 6:

  1. :alice a :Employee
  2. :acme a :Organisation
  3. :alice a :Person

Notice three things production engineers always trip on:

  • The closure is computed by repeated passes, not a single sweep — rdfs9 fed itself a new fact in pass 2.
  • rdfs2 is redundant here (rdfs9 already gave us Employee), but that's fine — closure deduplication is a set union, not a list append.
  • rdfs3 types the object — many engineers forget that domain/range fire both directions and treat range as 'optional'.

Visual — rdfs9 cascade

Click a node to focus its neighbourhood · drag to pan · scroll to zoom
  • instance
  • asserted
  • entailed

How rdfs9 fans out across a class hierarchy

Below: a single asserted :alice a :Manager (top) cascades down through rdfs:subClassOf chains and produces three entailed type triples. The arrows are rdfs:subClassOf; the dashed nodes are the entailed types.

Try mentally adding a fifth super-class — every existing instance of every sub-class instantly gains a fifth rdf:type triple. That is the fan-out cost a triple store pays at materialisation time.

Three production case studies

Real-world use cases

1. Schema.org product search

Schema.org publishes a deep class tree: Product → SomeProducts → IndividualProduct, and a parallel hierarchy for Offer, Review, etc. When Google indexes a page tagged <script type="application/ld+json">{ "@type": "Book", … }</script> it uses RDFS-style entailment to know that this Book is also a Product, also a CreativeWork, also a Thing. Without entailment, every publisher would have to redundantly tag a book as Book, Product, CreativeWork, Thing for it to surface in matching search filters. Entailment turns one type annotation into a working facet hierarchy.

2. Gene Ontology (GO) annotations

Biologists annotate a gene with one specific term, e.g. GENE_X enables 'mitochondrial transmembrane transport'. The GO has a deep is_a (≈ rdfs:subClassOf) tree above this term: transport → localization → biological process. A bioinformatician asking 'find every gene involved in any biological process' gets Gene_X back only because the materialised closure types it under all the parent terms. The GO consortium publishes both a 'lite' (asserted) and a 'full' (closed) release — same source data, exponentially different query power.

3. FIBO (Financial Industry Business Ontology)

FIBO uses sub-properties extensively: hasParty rdfs:subPropertyOf hasRelatedRole and hasParty rdfs:subPropertyOf hasContractualRelationship. A regulator's query 'list every contract that mentions Bank XYZ in any role' matches via hasContractualRelationship — and rdfs7 ensures every concrete hasParty, hasGuarantor, hasUnderwriter triple shows up in that result without the regulator having to enumerate the dozen specific sub-properties.

When not to materialise

Domain/range entailment can be a footgun. If :treats rdfs:domain :Doctor and you accidentally write :bob :treats :alice for a non-doctor Bob, RDFS will silently entail :bob a :Doctor. There is no exception, no validation error — open-world assumption means 'the data is consistent with Bob being a doctor, so we'll add it.' This is exactly why SHACL validation (lesson on shapes) is the right complement: SHACL closes the world for a given graph and rejects the triple instead of silently reclassifying Bob.

Make it stick

Pin the rules to a graph you actually own.

  • Pick one class hierarchy in your data (org chart, product taxonomy, anatomy) — how many entailed `rdf:type` triples would rdfs9 add for a single asserted instance?
  • Find one property whose `rdfs:domain` would *silently* reclassify subjects — what would break if a typo entailed the wrong type?
  • Would you materialise the RDFS closure (forward chaining) or rewrite at query time (backward chaining) for that graph? What tips the trade-off?

Tools & resources

Tools & resources

Reading in progress · 0 of 7 activities done