Drupal is a registered trademark of Dries Buytaert
cms 2.1.3 Update released for Drupal core (2.1.3)! drupal 10.5.11 Update released for Drupal core (10.5.11)! drupal 11.3.11 Update released for Drupal core (11.3.11)! drupal 11.2.13 Update released for Drupal core (11.2.13)! drupal 10.6.10 Update released for Drupal core (10.6.10)! cms 2.1.2 Update released for Drupal core (2.1.2)! drupal 11.1.10 Update released for Drupal core (11.1.10)! drupal 10.5.10 Update released for Drupal core (10.5.10)! drupal 10.4.10 Update released for Drupal core (10.4.10)! drupal 11.2.12 Update released for Drupal core (11.2.12)! drupal 11.3.10 Update released for Drupal core (11.3.10)! drupal 10.6.9 Update released for Drupal core (10.6.9)! drupal 10.6.8 Update released for Drupal core (10.6.8)! drupal 11.3.9 Update released for Drupal core (11.3.9)! drupal 11.3.8 Update released for Drupal core (11.3.8)! drupal 11.3.7 Update released for Drupal core (11.3.7)! drupal 11.2.11 Update released for Drupal core (11.2.11)! drupal 10.6.7 Update released for Drupal core (10.6.7)! drupal 10.5.9 Update released for Drupal core (10.5.9)! cms 2.1.1 Update released for Drupal core (2.1.1)!

child_entity

5 sites Security covered
View on drupal.org

This module helps you to create Entities which creating them depends on a parent entity.

Consider a Room in a House. The Room can only every be in one house. In this example Room is child and House is parent entity.

In order to use this module you have to:

  • Implement ChildEntityInterface or extend it
  • Use Child Entity Handlers, either directly in the Entity definition or extending them.
  • Define parent key in entity_keys section of the child entity annotation and use ChildEntityTrait
  • Add childBaseFieldDefinitions

This works in the same way as core's EntityOwnerTrait.

/**
 ************ other configuration ************
 *   handlers = {
 *     "list_builder" = "Drupal\child_entity\ChildEntityListBuilder",
 *     "views_data" = "Drupal\child_entity\ChildEntityViewsData",
 *     "form" = {
 *       "default" = "Drupal\child_entity\Form\ChildEntityForm",
 *     },
 *     "route_provider" = {
 *       "html" = "Drupal\child_entity\Routing\ChildEntityHtmlRouteProvider",
 *     },
 *     "access" = "Drupal\child_entity\ChildEntityAccessControlHandler",
 *   entity_keys = {
 *     "parent" = "house",
 *   },
 ************ other configuration ************
 */
class Room extends ContentEntityBase implements ChildEntityInterface {

  use ChildEntityTrait;

  /**
   * {@inheritdoc}
   */
  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
    $fields = parent::baseFieldDefinitions($entity_type);

    $fields += static::childBaseFieldDefinitions($entity_type);

    return $fields;
  }
}

Revision-able Entities and urlRouteParameters()

If your entity type also has revisions you may be overriding the urlRouteParameters() but you need to specify to use the one from the trait:

  use ChildEntityTrait {
    urlRouteParameters as childEntityUrlRouteParameters;
  }

  /**
   * {@inheritdoc}
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function urlRouteParameters($rel) {
    $uri_route_parameters = $this->childEntityUrlRouteParameters($rel);

    if ($rel === 'revision_revert' && $this instanceof RevisionableInterface) {
      $uri_route_parameters[$this->getEntityTypeId() . '_revision'] = $this->getRevisionId();
    }
    elseif ($rel === 'revision_delete' && $this instanceof RevisionableInterface) {
      $uri_route_parameters[$this->getEntityTypeId() . '_revision'] = $this->getRevisionId();
    }

    return $uri_route_parameters;
  }

Version 1

Version 1 of this module implemented Base classes that can be extended however this has limitations and version 2 uses Traits which allows the following:

class ChildNode extends Node implements ChildEntityInterface {

  use ChildEntityTrait;
}

Activity

Total releases
2
First release
Jan 2026
Latest release
3 months ago
Release cadence
14 days
Stability
50% stable

Releases

Version Type Release date
2.1.x-dev Dev Feb 8, 2026
2.0.0 Stable Jan 25, 2026