diff --git a/config/schema/page_manager.schema.yml b/config/schema/page_manager.schema.yml
index add031c..693e8aa 100644
--- a/config/schema/page_manager.schema.yml
+++ b/config/schema/page_manager.schema.yml
@@ -73,6 +73,25 @@ page_manager.page_variant.*:
             value:
               type: string
               label: 'Context value'
+    relationships:
+      type: sequence
+      label: 'Relationships'
+      sequence:
+        - type: page_manager.context_generator_plugin.[id]
+          label: 'Relationship'
+
+page_manager.context_generator_plugin:
+  type: mapping
+  mapping:
+    label:
+      type: label
+      label: 'Label of the context'
+    id:
+      type: string
+      label: 'Plugin id'
+
+page_manager.context_generator_plugin.*:
+  type: page_manager.context_generator_plugin
 
 page_manager.block_plugin.*:
   type: block.settings.[id]
diff --git a/page_manager.services.yml b/page_manager.services.yml
index 4d7db13..666a0d9 100644
--- a/page_manager.services.yml
+++ b/page_manager.services.yml
@@ -28,3 +28,6 @@ services:
     tags:
       - { name: event_subscriber }
     arguments: ['@current_route_match']
+  plugin.manager.context_generator:
+    class: Drupal\page_manager\Plugin\ContextGeneratorManager
+    parent: default_plugin_manager
diff --git a/page_manager_ui/page_manager_ui.routing.yml b/page_manager_ui/page_manager_ui.routing.yml
index 499171b..540937f 100644
--- a/page_manager_ui/page_manager_ui.routing.yml
+++ b/page_manager_ui/page_manager_ui.routing.yml
@@ -108,6 +108,24 @@ page_manager.static_context_delete:
   requirements:
     _entity_access: page_variant.update
 
+#### Relationships
+
+page_manager.relationship_select:
+  path: '/admin/structure/page_manager/manage/{page}/variant/{page_variant}/relationship/select'
+  defaults:
+    _controller: '\Drupal\page_manager_ui\Controller\PageManagerController::selectRelationship'
+    _title: 'Select relationship'
+  requirements:
+    _entity_access: page_variant.update
+
+page_manager.relationship_add:
+  path: '/admin/structure/page_manager/manage/{page}/variant/{page_variant}/relationship/add/{context_generator_id}'
+  defaults:
+    _form: '\Drupal\page_manager_ui\Form\RelationshipAddForm'
+    _title: 'Add new relationship'
+  requirements:
+    _entity_access: page_variant.update
+
 #### Variants
 
 page_manager.variant_select:
diff --git a/page_manager_ui/src/Controller/PageManagerController.php b/page_manager_ui/src/Controller/PageManagerController.php
index e957f69..4fc1e96 100644
--- a/page_manager_ui/src/Controller/PageManagerController.php
+++ b/page_manager_ui/src/Controller/PageManagerController.php
@@ -15,6 +15,7 @@
 use Drupal\ctools\Form\AjaxFormTrait;
 use Drupal\page_manager\PageInterface;
 use Drupal\page_manager\PageVariantInterface;
+use Drupal\page_manager\Plugin\ContextGeneratorManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -47,6 +48,13 @@ class PageManagerController extends ControllerBase {
   protected $variantManager;
 
   /**
+   * The context generator manager.
+   *
+   * @var \Drupal\page_manager\Plugin\ContextGeneratorManagerInterface
+   */
+  protected $contextGeneratorManager;
+
+  /**
    * The context handler.
    *
    * @var \Drupal\Core\Plugin\Context\ContextHandlerInterface
@@ -62,13 +70,16 @@ class PageManagerController extends ControllerBase {
    *   The condition manager.
    * @param \Drupal\Component\Plugin\PluginManagerInterface $variant_manager
    *   The variant manager.
+   * @param \Drupal\page_manager\Plugin\ContextGeneratorManagerInterface
+   *   The context generator manager.
    * @param \Drupal\Core\Plugin\Context\ContextHandlerInterface $context_handler
    *   The context handler.
    */
-  public function __construct(BlockManagerInterface $block_manager, PluginManagerInterface $condition_manager, PluginManagerInterface $variant_manager, ContextHandlerInterface $context_handler) {
+  public function __construct(BlockManagerInterface $block_manager, PluginManagerInterface $condition_manager, PluginManagerInterface $variant_manager, ContextGeneratorManagerInterface $context_generator_manager, ContextHandlerInterface $context_handler) {
     $this->blockManager = $block_manager;
     $this->conditionManager = $condition_manager;
     $this->variantManager = $variant_manager;
+    $this->contextGeneratorManager = $context_generator_manager;
     $this->contextHandler = $context_handler;
   }
 
@@ -80,6 +91,7 @@ public static function create(ContainerInterface $container) {
       $container->get('plugin.manager.block'),
       $container->get('plugin.manager.condition'),
       $container->get('plugin.manager.display_variant'),
+      $container->get('plugin.manager.context_generator'),
       $container->get('context.handler')
     );
   }
@@ -327,6 +339,48 @@ public function selectBlock(Request $request, PageVariantInterface $page_variant
   }
 
   /**
+   * Presents a list of relationships to add to the variant.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   * @param \Drupal\page_manager\PageVariantInterface $page_variant
+   *   The page entity.
+   *
+   * @return array
+   *   The relationship selection page.
+   */
+  public function selectRelationship(Request $request, PageVariantInterface $page_variant) {
+    // Add a section containing the available relationships to be added to the variant.
+    $build = [
+      '#type' => 'container',
+      '#attached' => [
+        'library' => [
+          'core/drupal.ajax',
+        ],
+      ],
+    ];
+    $build['content'] = [
+      '#theme' => 'links',
+    ];
+    $available_plugins = $this->contextGeneratorManager->getDefinitionsForContexts($page_variant->getContexts());
+    foreach ($available_plugins as $plugin_id => $plugin_definition) {
+      // Add a link for each available block within each region.
+      $build['content']['#links'][$plugin_id] = [
+        'title' => $plugin_definition['label'],
+        'url' => Url::fromRoute('page_manager.relationship_add', [
+          'page' => $page_variant->get('page'),
+          'page_variant' => $page_variant->id(),
+          'context_generator_id' => $plugin_id,
+          'region' => $request->query->get('region'),
+        ]),
+        'attributes' => $this->getAjaxAttributes(),
+      ];
+    }
+    return $build;
+  }
+
+
+  /**
    * Build the page variant entity add form.
    *
    * @param \Drupal\page_manager\PageInterface $page
diff --git a/page_manager_ui/src/Form/PageVariantEditForm.php b/page_manager_ui/src/Form/PageVariantEditForm.php
index 3cf0992..525bef7 100644
--- a/page_manager_ui/src/Form/PageVariantEditForm.php
+++ b/page_manager_ui/src/Form/PageVariantEditForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\page_manager_ui\Form;
 
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
 use Drupal\ctools\Form\AjaxFormTrait;
@@ -40,6 +41,8 @@ public function form(array $form, FormStateInterface $form_state) {
 
     $form['context'] = $this->buildContextForm();
 
+    $form['relationships'] = $this->buildRelationshipForm();
+
     return $form;
   }
 
@@ -305,6 +308,12 @@ protected function buildContextForm() {
     $attributes = $this->getAjaxAttributes();
     $add_button_attributes = $this->getAjaxButtonAttributes();
 
+    // Make a lookup table of relationships to easily find them by id.
+    $relationships = [];
+    foreach ($page_variant->getRelationships() as $relationship) {
+      $relationships[$relationship['id']] = $relationship;
+    }
+
     $form = [
       '#type' => 'details',
       '#title' => $this->t('Available context'),
@@ -336,6 +345,11 @@ protected function buildContextForm() {
     ];
     $contexts = $page_variant->getContexts();
     foreach ($contexts as $name => $context) {
+      // Skip relationships - they get their own section.
+      if (isset($relationships[$name])) {
+        continue;
+      }
+
       $context_definition = $context->getContextDefinition();
 
       $row = [];
@@ -383,6 +397,103 @@ protected function buildContextForm() {
   }
 
   /**
+   * Builds the relationship form for a variant.
+   *
+   * @return array
+   */
+  protected function buildRelationshipForm() {
+    /** @var \Drupal\page_manager\PageVariantInterface $page_variant */
+    $page_variant = $this->getEntity();
+
+    // Set up the attributes used by a modal to prevent duplication later.
+    $attributes = $this->getAjaxAttributes();
+    $add_button_attributes = $this->getAjaxButtonAttributes();
+
+    $form = [
+      '#type' => 'details',
+      '#title' => $this->t('Relationships'),
+      '#open' => TRUE,
+    ];
+    $form['add'] = [
+      '#type' => 'link',
+      '#title' => $this->t('Add new relationship'),
+      '#url' => Url::fromRoute('page_manager.relationship_select', [
+        'page' => $page_variant->get('page'),
+        'page_variant' => $page_variant->id(),
+      ]),
+      '#attributes' => $add_button_attributes,
+      '#attached' => [
+        'library' => [
+          'core/drupal.ajax',
+        ],
+      ],
+    ];
+    $form['available_context'] = [
+      '#type' => 'table',
+      '#header' => [
+        $this->t('Label'),
+        $this->t('Name'),
+        $this->t('Token'),
+        $this->t('Operations'),
+      ],
+      '#empty' => $this->t('There is no available context.'),
+    ];
+    /*
+    foreach ($page_variant->getRelationships() as $token => $relationship) {
+      $row = [];
+      $row['label'] = [
+        '#markup' => $relationship['label'],
+      ];
+      $row['machine_name'] = [
+        '#markup' => $relationship['id'],
+      ];
+      $row['token'] = [
+        '#markup' => $token,
+      ];
+
+      // Add operation links if the context is a static context.
+      $operations = [];
+      $operations['edit'] = [
+        'title' => $this->t('Edit'),
+        'url' => Url::fromRoute('page_manager.relationship_edit', [
+          'page' => $page_variant->get('page'),
+          'page_variant' => $page_variant->id(),
+          'name' => $token,
+        ]),
+        'attributes' => $attributes,
+      ];
+      $operations['delete'] = [
+        'title' => $this->t('Delete'),
+        'url' => Url::fromRoute('page_manager.relationship_delete', [
+          'page' => $page_variant->get('page'),
+          'page_variant' => $page_variant->id(),
+          'name' => $token,
+        ]),
+        'attributes' => $attributes,
+      ];
+      $row['operations'] = [
+        '#type' => 'operations',
+        '#links' => $operations,
+      ];
+
+      $form['available_context'][$name] = $row;
+    }
+    */
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
+    // Unset 'relationships' because it doesn't hold the complete data.
+    $form_state->unsetValue('relationships');
+
+    parent::copyFormValuesToEntity($entity, $form, $form_state);
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function save(array $form, FormStateInterface $form_state) {
diff --git a/src/Annotation/ContextGenerator.php b/src/Annotation/ContextGenerator.php
new file mode 100644
index 0000000..c4f1dfa
--- /dev/null
+++ b/src/Annotation/ContextGenerator.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\page_manager\Annotation\ContextGenerator.
+ */
+
+namespace Drupal\page_manager\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines a Context Generator item annotation object.
+ *
+ * @see \Drupal\page_manager\Plugin\ContextGeneratorManager
+ * @see plugin_api
+ *
+ * @Annotation
+ */
+class ContextGenerator extends Plugin {
+
+  /**
+   * The plugin ID.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The label of the plugin.
+   *
+   * @var \Drupal\Core\Annotation\Translation
+   *
+   * @ingroup plugin_translatable
+   */
+  public $label;
+
+}
diff --git a/src/Entity/PageVariant.php b/src/Entity/PageVariant.php
index a433b16..d4a415b 100644
--- a/src/Entity/PageVariant.php
+++ b/src/Entity/PageVariant.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Plugin\DefaultLazyPluginCollection;
 use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection;
 use Drupal\page_manager\PageVariantInterface;
 
@@ -41,6 +42,7 @@
  *     "selection_criteria",
  *     "selection_logic",
  *     "static_context",
+ *     "relationships",
  *   },
  *   lookup_keys = {
  *     "page"
@@ -129,6 +131,15 @@ class PageVariant extends ConfigEntityBase implements PageVariantInterface {
   protected $static_context = [];
 
   /**
+   * Relationship references.
+   *
+   * A list of arrays with the keys id, and label.
+   *
+   * @var array[]
+   */
+  protected $relationships = [];
+
+  /**
    * The plugin collection that holds the single variant plugin instance.
    *
    * @var \Drupal\Core\Plugin\DefaultSingleLazyPluginCollection
@@ -143,6 +154,13 @@ class PageVariant extends ConfigEntityBase implements PageVariantInterface {
   protected $selectionConditionCollection;
 
   /**
+   * The plugin collection that holds the context generator plugins.
+   *
+   * @var \Drupal\Component\Plugin\LazyPluginCollection
+   */
+  protected $relationshipCollection;
+
+  /**
    * {@inheritdoc}
    */
   protected function invalidateTagsOnSave($update) {
@@ -200,6 +218,7 @@ public function getPluginCollections() {
     return [
       'selection_criteria' => $this->getSelectionConditions(),
       'variant_settings' => $this->getVariantPluginCollection(),
+      'relationships' => $this->getRelationships(),
     ];
   }
 
@@ -247,7 +266,10 @@ public function getContexts() {
     if (is_null($this->contexts)) {
       $static_contexts = $this->getContextMapper()->getContextValues($this->getStaticContexts());
       $page_contexts = $this->getPage()->getContexts();
-      $this->contexts = array_merge($static_contexts, $page_contexts);
+      $contexts = array_merge($static_contexts, $page_contexts);
+      // @todo: get contexts from relationships somehow.
+      $relationships = [];
+      $this->contexts = array_merge($relationships, $static_contexts, $page_contexts);
     }
     return $this->contexts;
   }
@@ -363,6 +385,44 @@ public function removeStaticContext($name) {
   /**
    * {@inheritdoc}
    */
+  protected function getRelationshipConfiguration() {
+    return $this->get('relationships');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRelationships() {
+    if (!$this->relationshipCollection) {
+      $this->relationshipCollection = new DefaultLazyPluginCollection($this->getContextGeneratorManager(), $this->getRelationshipConfiguration());
+    }
+    return $this->relationshipCollection;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRelationship($name) {
+    // @todo: Implement me!
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addRelationship($name, array $configuration) {
+    // @todo: Implement me!
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function removeRelationship($name) {
+    // @todo: Implement me!
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   protected function urlRouteParameters($rel) {
     $parameters = parent::urlRouteParameters($rel);
     $parameters['page'] = $this->get('page');
@@ -405,6 +465,15 @@ protected function getConditionManager() {
   }
 
   /**
+   * Wraps the context generator plugin manager.
+   *
+   * @return \Drupal\page_manager\Plugin\ContextGeneratorManagerInterface
+   */
+  protected function getContextGeneratorManager() {
+    return \Drupal::service('plugin.manager.context_generator');
+  }
+
+  /**
    * Wraps the context mapper.
    *
    * @return \Drupal\page_manager\ContextMapperInterface
diff --git a/src/PageVariantInterface.php b/src/PageVariantInterface.php
index 12110c7..a88b59a 100644
--- a/src/PageVariantInterface.php
+++ b/src/PageVariantInterface.php
@@ -148,4 +148,43 @@ public function setStaticContext($name, $configuration);
    */
   public function removeStaticContext($name);
 
+  /**
+   * Returns the relationships for this variant entity.
+   *
+   * @return \Drupal\page_manager\Plugin\ContextGeneratorInterface[]|\Drupal\Core\Plugin\DefaultSingleLazyPluginCollection
+   *   The context generator plugins.
+   */
+  public function getRelationships();
+
+  /**
+   * Retrieves a specific relationship.
+   *
+   * @param string $name
+   *   The context name.
+   *
+   * @return \Drupal\page_manager\Plugin\ContextGeneratorInterface
+   *   The context generator plugin.
+   */
+  public function getRelationship($name);
+
+  /**
+   * Adds a relationship.
+   *
+   * @param string $name
+   *   The context name.
+   * @param array $configuration
+   *   Configuration of the selection criteria.
+   */
+  public function addRelationship($name, array $configuration);
+
+  /**
+   * Removes a specific relationship.
+   *
+   * @param string $name
+   *   The context name.
+   *
+   * @return $this
+   */
+  public function removeRelationship($name);
+
 }
diff --git a/src/Plugin/ContextGenerator/TypedDataRelationship.php b/src/Plugin/ContextGenerator/TypedDataRelationship.php
new file mode 100644
index 0000000..c1c2908
--- /dev/null
+++ b/src/Plugin/ContextGenerator/TypedDataRelationship.php
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\page_manager\Plugin\ContextGenerator\TypedDataRelationship
+ */
+
+namespace Drupal\page_manager\Plugin\ContextGenerator;
+
+use Drupal\Core\Plugin\Context\Context;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\TypedData\DataReferenceInterface;
+use Drupal\page_manager\Plugin\ContextGeneratorBase;
+
+/**
+ * Generates new contexts based on typed data relationships on existing contexts.
+ *
+ * @ContextGenerator(
+ *   id = "typed_data_relationship",
+ *   deriver = "\Drupal\page_manager\Plugin\Deriver\TypedDataRelationshipDeriver",
+ * )
+ */
+class TypedDataRelationship extends ContextGeneratorBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function generateContext() {
+    $plugin_definition = $this->getPluginDefinition();
+
+    $context_definition = new ContextDefinition($plugin_definition['data_type'], $plugin_definition['label']);
+    $context_value = NULL;
+
+    // If the 'base' context has a value, then get the property value to put on
+    // the context (otherwise, mapping hasn't occurred yet and we just want to
+    // return the context with the right definition and no value).
+    $contexts = $this->getContexts();
+    $base_context = isset($contexts['base']) ? $contexts['base'] : NULL;
+    if ($base_context && $base_context->hasContextValue()) {
+      /** @var \Drupal\Core\TypedData\ComplexDataInterface $base */
+      $base = $contexts['base']->getContextValue();
+      $name = $plugin_definition['property_name'];
+      $data = $base->get($name);
+      if ($data instanceof DataReferenceInterface) {
+        $data = $data->getTarget();
+      }
+      $context_value = $data->getValue();
+    }
+
+    return new Context($context_definition, $context_value);
+
+  }
+
+}
\ No newline at end of file
diff --git a/src/Plugin/ContextGeneratorBase.php b/src/Plugin/ContextGeneratorBase.php
new file mode 100644
index 0000000..612e493
--- /dev/null
+++ b/src/Plugin/ContextGeneratorBase.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\page_manager\Plugin\ContextGeneratorBase.
+ */
+
+namespace Drupal\page_manager\Plugin;
+
+use Drupal\Core\Plugin\ContextAwarePluginBase;
+
+/**
+ * Base class for Context Generator plugins.
+ */
+abstract class ContextGeneratorBase extends ContextAwarePluginBase implements ContextGeneratorInterface {
+
+}
diff --git a/src/Plugin/ContextGeneratorInterface.php b/src/Plugin/ContextGeneratorInterface.php
new file mode 100644
index 0000000..fea93e3
--- /dev/null
+++ b/src/Plugin/ContextGeneratorInterface.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\page_manager\Plugin\ContextGeneratorInterface.
+ */
+
+namespace Drupal\page_manager\Plugin;
+
+use Drupal\Component\Plugin\DerivativeInspectionInterface;
+use Drupal\Component\Plugin\PluginInspectionInterface;
+
+/**
+ * Interface for plugins that generate a new context based on configuration.
+ */
+interface ContextGeneratorInterface extends PluginInspectionInterface, DerivativeInspectionInterface {
+
+  /**
+   * Generates a context based on this plugin's configuration.
+   *
+   * @return \Drupal\Core\Plugin\Context\Context
+   */
+  public function generateContext();
+
+}
diff --git a/src/Plugin/ContextGeneratorManager.php b/src/Plugin/ContextGeneratorManager.php
new file mode 100644
index 0000000..32fc2a6
--- /dev/null
+++ b/src/Plugin/ContextGeneratorManager.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\page_manager\Plugin\ContextGeneratorManager.
+ */
+
+namespace Drupal\page_manager\Plugin;
+
+use Drupal\Core\Plugin\Context\ContextAwarePluginManagerTrait;
+use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\page_manager\Plugin\ContextGeneratorManagerInterface;
+
+/**
+ * Provides the Context Generator plugin manager.
+ */
+class ContextGeneratorManager extends DefaultPluginManager implements ContextGeneratorManagerInterface {
+
+  use ContextAwarePluginManagerTrait;
+
+  /**
+   * Constructor for ContextGeneratorManager objects.
+   *
+   * @param \Traversable $namespaces
+   *   An object that implements \Traversable which contains the root paths
+   *   keyed by the corresponding namespace to look for plugin implementations.
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+   *   Cache backend instance to use.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke the alter hook with.
+   */
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Plugin/ContextGenerator', $namespaces, $module_handler, 'Drupal\page_manager\Plugin\ContextGeneratorInterface', 'Drupal\page_manager\Annotation\ContextGenerator');
+
+    $this->alterInfo('page_manager_context_generator_info');
+    $this->setCacheBackend($cache_backend, 'page_manager_context_generator_plugins');
+  }
+
+}
diff --git a/src/Plugin/ContextGeneratorManagerInterface.php b/src/Plugin/ContextGeneratorManagerInterface.php
new file mode 100644
index 0000000..38f5483
--- /dev/null
+++ b/src/Plugin/ContextGeneratorManagerInterface.php
@@ -0,0 +1,18 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\page_manager\Plugin\ContextGeneratorManagerInterface.
+ */
+
+namespace Drupal\page_manager\Plugin;
+
+use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
+use Drupal\Core\Plugin\Context\ContextAwarePluginManagerInterface;
+
+/**
+ * Interface for context generator plugin manager.
+ */
+interface ContextGeneratorManagerInterface extends ContextAwarePluginManagerInterface, CachedDiscoveryInterface {
+
+}
\ No newline at end of file
diff --git a/src/Plugin/Deriver/TypedDataRelationshipDeriver.php b/src/Plugin/Deriver/TypedDataRelationshipDeriver.php
new file mode 100644
index 0000000..481ad0d
--- /dev/null
+++ b/src/Plugin/Deriver/TypedDataRelationshipDeriver.php
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\page_manager\Plugin\Deriver\TypedDataRelationshipDeriver.
+ */
+
+namespace Drupal\page_manager\Plugin\Deriver;
+
+use Drupal\Component\Plugin\Derivative\DeriverBase;
+use Drupal\Core\Entity\TypedData\EntityDataDefinitionInterface;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Core\TypedData\ComplexDataDefinitionInterface;
+use Drupal\Core\TypedData\ComplexDataInterface;
+use Drupal\Core\TypedData\DataReferenceDefinitionInterface;
+use Drupal\Core\TypedData\TypedDataManagerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+class TypedDataRelationshipDeriver extends DeriverBase implements ContainerDeriverInterface {
+
+  use StringTranslationTrait;
+
+  /**
+   * @var \Drupal\Core\TypedData\TypedDataManagerInterface
+   */
+  protected $typedDataManager;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(TypedDataManagerInterface $typed_data_manager, TranslationInterface $string_translation) {
+    $this->typedDataManager = $typed_data_manager;
+    $this->stringTranslation = $string_translation;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, $base_plugin_id) {
+    return new static(
+      $container->get('typed_data_manager'),
+      $container->get('string_translation')
+    );
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions($base_plugin_definition) {
+    foreach ($this->typedDataManager->getDefinitions() as $data_type => $definition) {
+      if (is_subclass_of($definition['class'], ComplexDataInterface::class, TRUE)) {
+        /** @var \Drupal\Core\TypedData\ComplexDataDefinitionInterface $base_definition */
+        $base_definition = $this->typedDataManager->createDataDefinition($data_type);
+        foreach ($base_definition->getPropertyDefinitions() as $property_name => $property_definition) {
+          $derivative = $base_plugin_definition;
+
+          $derivative['label'] = $this->t('@property from @base', [
+            '@property' => $property_definition->getLabel(),
+            '@base' => $definition['label'],
+          ]);
+          $derivative['data_type'] = $property_definition instanceof DataReferenceDefinitionInterface ? $property_definition->getTargetDefinition()->getDataType() : $property_definition->getDataType();
+          $derivative['property_name'] = $property_name;
+          $derivative['context'] = [
+            'base' => new ContextDefinition($base_definition->getDataType(), $base_definition->getLabel(), TRUE),
+          ];
+
+          $this->derivatives[$data_type . ':' . $property_name] = $derivative;
+        }
+      }
+    }
+
+    return $this->derivatives;
+  }
+
+}
\ No newline at end of file
