Theory
RDFS reads rdfs:domain and rdfs:range as typing rules, not constraints:
:teaches rdfs:domain :Master ;
rdfs:range :Ninja .
From :Splinter :teaches :Donatello ., a reasoner entails :Splinter a :Master . and :Donatello a :Ninja .. Surprising at first!
RDFS infers, it doesn't reject. Coming from SQL or OO languages, your instinct is to read rdfs:domain :Master as the subject must already be a :Master. RDFS does the opposite: it concludes the subject is a Master because you used :teaches. So an unintended :teaches use will silently classify the wrong thing as a :Master. To actually reject bad data, you'll want a SHACL shape (Level 6).
