# Lesson 5.2: Defining type hierarchies

## [](#_defining_entity_type_hierarchies)Defining entity type hierarchies

To define type hierarchies, we use the same Define queries as when defining individual types. The following query shows how we can define a hierarchy of book types.

```typeql
define
entity book;
entity paperback, sub book;
entity hardback, sub book;
entity ebook, sub book;
```

_→ Commit_

To make one type a subtype of another, we simply replace the root type with the intended **supertype** in the `sub` statement that defines that type. When defined in a type hierarchy, subtypes will **inherit** all the owned attributes and played roles of their supertypes. Consider the following Define query where we assign a number of ownerships and roles to `book`.

```typeql
define
entity book owns title,
  owns page-count,
  owns genre,
  owns price,
  plays publishing:published,
  plays order-line:item,
  plays rating:rated,
  plays promotion-inclusion:item;
attribute title, value string;
attribute page-count, value integer;
attribute genre, value string;
```

_→ Commit_

`paperback`, `hardback`, and `ebook` will inherit all of these capabilities from `book` without having to explicitly declare this to be the case. This will even apply to new subtypes of `book` defined in the future! If we want capabilities that only apply to certain subtypes, then we can declare them directly on those types only.

```typeql
define
entity paperback, owns stock;
entity hardback, owns stock;
attribute stock, value integer;
```

_→ Commit_

This allows paperbacks and hardbacks to have stock levels, but not ebooks.

Exercise

Write a query to define an entity type `company` with two subtypes `publisher` and `courier`, and define the following capabilities:

*   All companies can own attributes of the existing type `name`.
    
*   Publishers can also play the existing role `publishing:publisher`.
    
*   Couriers can also play the existing role `delivery:deliverer`.
    

Sample solution

```typeql
define
entity company,
  owns name;
entity publisher,
  sub company,
  plays publishing:publisher;
entity courier,
  sub company,
  plays delivery:deliverer;
```

_→ Commit_

## [](#_defining_abstract_types)Defining abstract types

Abstract types cannot be directly instantiated, much like abstract classes in OOP. An abstract type can only be instantiated via its subtypes. To make a type abstract, we use an `@abstract` annotation. The following Define query makes the existing types `book` and `company` abstract.

```typeql
define
entity book @abstract;
entity company @abstract;
```

_→ Commit_

Now `book` can only be instantiated through `paperback`, `hardback`, or `ebook`, and `company` can only be instantiated through `publisher` or `courier`.

Exercise

Write a query to define an abstract entity type `place` with three subtypes, `country`, `state`, and `city`, and define the following capabilities:

*   All places can own attributes of the existing type `name`.
    
*   All places can play the existing role `locating:location`.
    
*   All places can play the existing role `locating:located`.
    

Sample solution

```typeql
define
entity place @abstract,
    owns name,
    plays locating:location,
    plays locating:located;
entity country, sub place;
entity state, sub place;
entity city, sub place;
```

_→ Commit_

## [](#_defining_relation_type_hierarchies)Defining relation type hierarchies

Relation type hierarchies are defined in the same way as entity type hierarchies. When defined in a hierarchy, subtypes of a relation type inherit all its roles. The following Define query defines a relation type `contribution` and three subtypes.

```typeql
define
relation contribution,
    relates work,
    relates contributor;
relation authoring, sub contribution;
relation editing, sub contribution;
relation illustrating, sub contribution;
```

_→ Commit_

Here, `authoring`, `editing`, and `illustrating` inherit the roles `work` and `contributor` from `contribution`. This would allow instantiation of the following relation types:

*   `contribution` with roles `contribution:work` and `contribution:contributor`
    
*   `authoring` with roles `contribution:work` and `contribution:contributor`
    
*   `editing` with roles `contribution:work` and `contribution:contributor`
    
*   `illustrating` with roles `contribution:work` and `contribution:contributor`
    

We could also define new roles on a specific subtype using the `relates` keyword on that subtype, in the same way we can define capabilities on specific subtypes using the `owns` and `plays` keywords on them. A new role can be made to **override** an existing role of a parent relation using the `as` keyword. In the following query, the roles `author`, `editor`, and `illustrator` override the inherited `contributor` role.

```typeql
define
relation authoring, relates author as contributor;
relation editing, relates editor as contributor;
relation illustrating, relates illustrator as contributor;
```

_→ Commit_

This would instead allow instantiation of the following relation types:

*   `contribution` with roles `contribution:work` and `contribution:contributor`
    
*   `authoring` with roles `contribution:work` and `authoring:author`
    
*   `editing` with roles `contribution:work` and `editing:editor`
    
*   `illustrating` with roles `contribution:work` and `illustrating:illustrator`
    

An **overridden role** defines a subtype of the role, and makes the role abstract in the sub-relation. In other words, you get a new role that can be used in place of the parent role, and you cannot use the parent role in the sub relation.

Exercise

Write a query to define the following new role players:

*   The existing type `book` playing `contribution:work`.
    
*   The existing type `contributor` playing `contribution:contributor` and its three subtypes.
    

Sample solution

```typeql
define
entity book, plays contribution:work;
entity contributor, plays contribution:contributor;
entity contributor, plays authoring:author;
entity contributor, plays editing:editor;
entity contributor, plays illustrating:illustrator;
```

_→ Commit_

With this schema, it is no longer possible to instantiate `authoring`, `editing`, and `illustrating` with the `contribution:contributor` role. However, it is still possible to query them via that role, as the overriding roles `authoring:author`, `editing:editor`, and `illustrating:illustrator` are considered to be its **subtypes**. The `match` clause of the following Fetch query would match instances of `contributor`, `authoring`, `editing`, and `illustrating`, and contributor names would be returned for all contributor roles.

```typeql
match
contribution (work: $book, contributor: $contributor);
fetch {
  "title": $book.title,
  "name": $contributor.name
};
```

Exercise

Modify the above Fetch query to retrieve only author names instead of all contributor names.

Sample solution

```typeql
match
authoring (work: $book, author: $contributor);
fetch {
  "title": $book.title,
  "name": $contributor.name,
};
```

Now instead modify it to retrieve only names of contributors who have made miscellaneous contributions (i.e. those in direct instances of `contribution` and not its subtypes).

Sample solution

```typeql
match
$rel isa! contribution, links (work: $book, contributor: $contributor);
fetch {
  "title": $book.title,
  "name": $contributor.name,
};
```

Notice we have used the `isa!` keyword.

## [](#_defining_attribute_type_hierarchies)Defining attribute type hierarchies

Attribute types can also be defined hierarchically.

```typeql
define
attribute isbn value string;
attribute isbn-13 sub isbn;
attribute isbn-10 sub isbn;
```

_→ Commit_

Value types of attribute types are inherited by their subtypes. In this case, `isbn-13` and `isbn-10` inherit the `string` value type.

If you don’t want omit a value type in the super type, to allow different value types in sub types, you must make the attribute type abstract:

```typeql
define
attribute id @abstract;
attribute email-id, sub id, value string;
attribute numerical-id, sub id, value integer;
```

[Defining individual types](../5.1-defining-individual-types/index.md) [Defining constraints](../5.3-defining-constraints/index.md)

[Edit on GitHub](https://github.com/typedb/typedb-docs/edit/3.x-development/academy/modules/ROOT/pages/5-defining-schemas/5.2-defining-type-hierarchies.adoc) Edit this page on GitHub.