diff --git a/core/lib/Drupal/Core/Entity/Plugin/DataType/ConfigEntityAdapter.php b/core/lib/Drupal/Core/Entity/Plugin/DataType/ConfigEntityAdapter.php
index 093c77dd16..55a8bba0b9 100644
--- a/core/lib/Drupal/Core/Entity/Plugin/DataType/ConfigEntityAdapter.php
+++ b/core/lib/Drupal/Core/Entity/Plugin/DataType/ConfigEntityAdapter.php
@@ -2,7 +2,9 @@
 
 namespace Drupal\Core\Entity\Plugin\DataType;
 
+use Drupal\Core\Config\TypedConfigManagerInterface;
 use Drupal\Core\TypedData\Exception\MissingDataException;
+use Drupal\Core\TypedData\TypedDataManagerInterface;
 
 /**
  * Enhances EntityAdapter for config entities.
@@ -16,6 +18,13 @@ class ConfigEntityAdapter extends EntityAdapter {
    */
   protected $entity;
 
+  /**
+   * The typed config manager.
+   *
+   * @var \Drupal\Core\Config\TypedConfigManagerInterface
+   */
+  protected $typedConfigManager;
+
   /**
    * {@inheritdoc}
    */
@@ -68,10 +77,31 @@ public function getIterator() {
   }
 
   /**
-   * Gets the typed data manager.
+   * Gets the typed config manager.
    *
    * @return \Drupal\Core\Config\TypedConfigManagerInterface
-   *   The typed data manager.
+   *   The typed config manager.
+   */
+  protected function getTypedConfigManager() {
+    if (empty($this->typedConfigManager)) {
+      // Use the typed data manager if it is also the typed config manager.
+      // @todo Remove this in https://www.drupal.org/node/3011137.
+      $typed_data_manager = $this->getTypedDataManager();
+      if ($typed_data_manager instanceof TypedConfigManagerInterface) {
+        $this->typedConfigManager = $typed_data_manager;
+      }
+      else {
+        $this->typedConfigManager = \Drupal::service('config.typed');
+      }
+    }
+
+    return $this->typedConfigManager;
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @todo Remove this in https://www.drupal.org/node/3011137.
    */
   public function getTypedDataManager() {
     if (empty($this->typedDataManager)) {
@@ -81,6 +111,19 @@ public function getTypedDataManager() {
     return $this->typedDataManager;
   }
 
+  /**
+   * {@inheritdoc}
+   *
+   * @todo Remove this in https://www.drupal.org/node/3011137.
+   */
+  public function setTypedDataManager(TypedDataManagerInterface $typed_data_manager) {
+    $this->typedDataManager = $typed_data_manager;
+    if ($typed_data_manager instanceof TypedConfigManagerInterface) {
+      $this->typedConfigManager = $typed_data_manager;
+    }
+    return $this;
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -97,7 +140,7 @@ public function applyDefaultValue($notify = TRUE) {
    *   The typed data.
    */
   protected function getConfigTypedData() {
-    return $this->getTypedDataManager()->createFromNameAndData($this->entity->getConfigDependencyName(), $this->entity->toArray());
+    return $this->getTypedConfigManager()->createFromNameAndData($this->entity->getConfigDependencyName(), $this->entity->toArray());
   }
 
 }
diff --git a/core/lib/Drupal/Core/Plugin/Context/Context.php b/core/lib/Drupal/Core/Plugin/Context/Context.php
index a33eca2a45..14407ea1ab 100644
--- a/core/lib/Drupal/Core/Plugin/Context/Context.php
+++ b/core/lib/Drupal/Core/Plugin/Context/Context.php
@@ -6,6 +6,7 @@
 use Drupal\Component\Plugin\Exception\ContextException;
 use Drupal\Core\Cache\CacheableDependencyInterface;
 use Drupal\Core\Cache\CacheableMetadata;
+use Drupal\Core\DependencyInjection\DependencySerializationTrait;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\TypedData\TypedDataTrait;
 
@@ -14,6 +15,7 @@
  */
 class Context extends ComponentContext implements ContextInterface {
 
+  use DependencySerializationTrait;
   use TypedDataTrait;
 
   /**
diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php
index 9d8c81f588..f4460559d6 100644
--- a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php
+++ b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php
@@ -312,14 +312,36 @@ public function getDataDefinition() {
     return $definition;
   }
 
+  /**
+   * Checks if this definition's data type matches that of the given context.
+   *
+   * @param \Drupal\Core\Plugin\Context\ContextInterface $context
+   *   The context to test against.
+   *
+   * @return bool
+   *   TRUE if the data types match, otherwise FALSE.
+   */
+  protected function dataTypeMatches(ContextInterface $context) {
+    $this_type = $this->getDataType();
+    $that_type = $context->getContextDefinition()->getDataType();
+
+    return (
+      // 'any' means all data types are supported.
+      $this_type === 'any' ||
+      $this_type === $that_type ||
+      // Allow a more generic data type like 'entity' to be fulfilled by a more
+      // specific data type like 'entity:user'. However, if this type is more
+      // specific, do not consider a more generic type to be a match.
+      strpos($that_type, "$this_type:") === 0
+    );
+  }
+
   /**
    * {@inheritdoc}
    */
   public function isSatisfiedBy(ContextInterface $context) {
     $definition = $context->getContextDefinition();
-    // If the data types do not match, this context is invalid unless the
-    // expected data type is any, which means all data types are supported.
-    if ($this->getDataType() != 'any' && $definition->getDataType() != $this->getDataType()) {
+    if (!$this->dataTypeMatches($context)) {
       return FALSE;
     }
 
diff --git a/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php b/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php
index a5d453ae58..449996710e 100644
--- a/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php
+++ b/core/lib/Drupal/Core/TypedData/Validation/RecursiveContextualValidator.php
@@ -126,10 +126,16 @@ protected function validateNode(TypedDataInterface $data, $constraints = NULL, $
     $metadata = $this->metadataFactory->getMetadataFor($data);
     $cache_key = spl_object_hash($data);
     $property_path = $is_root_call ? '' : PropertyPath::append($previous_path, $data->getName());
+
+    // Prefer a specific instance of the typed data manager stored by the data
+    // if it is available. This is necessary for specialized typed data objects,
+    // for example those using the typed config subclass of the manager.
+    $typed_data_manager = method_exists($data, 'getTypedDataManager') ? $data->getTypedDataManager() : $this->typedDataManager;
+
     // Pass the canonical representation of the data as validated value to
     // constraint validators, such that they do not have to care about Typed
     // Data.
-    $value = $this->typedDataManager->getCanonicalRepresentation($data);
+    $value = $typed_data_manager->getCanonicalRepresentation($data);
     $this->context->setNode($value, $data, $metadata, $property_path);
 
     if (isset($constraints) || !$this->context->isGroupValidated($cache_key, Constraint::DEFAULT_GROUP)) {
diff --git a/core/modules/layout_builder/layout_builder.module b/core/modules/layout_builder/layout_builder.module
index 5d7c60615c..9b908fea7c 100644
--- a/core/modules/layout_builder/layout_builder.module
+++ b/core/modules/layout_builder/layout_builder.module
@@ -202,3 +202,15 @@ function layout_builder_block_content_access(EntityInterface $entity, $operation
   }
   return AccessResult::forbidden();
 }
+
+/**
+ * Implements hook_layout_builder_section_storage_alter().
+ */
+function layout_builder_layout_builder_section_storage_alter(array &$definitions) {
+  // The \Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage
+  // plugin defines the entity context via its annotation but cannot specify the
+  // constraint inline.
+  /** @var \Drupal\layout_builder\SectionStorage\SectionStorageDefinition[] $definitions */
+  $definitions['overrides']->getContextDefinition('entity')
+    ->addConstraint('EntityHasField', 'layout_builder__layout');
+}
diff --git a/core/modules/layout_builder/src/Annotation/SectionStorage.php b/core/modules/layout_builder/src/Annotation/SectionStorage.php
index 42f4a47fe6..73924be8ad 100644
--- a/core/modules/layout_builder/src/Annotation/SectionStorage.php
+++ b/core/modules/layout_builder/src/Annotation/SectionStorage.php
@@ -22,6 +22,30 @@ class SectionStorage extends Plugin {
    */
   public $id;
 
+  /**
+   * The plugin weight, optional (defaults to 0).
+   *
+   * When an entity with layout is rendered, section storage plugins are
+   * checked, in order of their weight, to determine which one should be used
+   * to render the layout.
+   *
+   * @var int
+   */
+  public $weight = 0;
+
+  /**
+   * Any required context definitions, optional.
+   *
+   * When an entity with layout is rendered, all section storage plugins which
+   * match a particular set of contexts are checked, in order of their weight,
+   * to determine which plugin should be used to render the layout.
+   *
+   * @var array
+   *
+   * @see \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::getRuntimeSections()
+   */
+  public $context = [];
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
index 0118768f77..801c232c8e 100644
--- a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
+++ b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
@@ -9,6 +9,7 @@
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\layout_builder\LayoutEntityHelperTrait;
 use Drupal\layout_builder\Section;
 use Drupal\layout_builder\SectionComponent;
 use Drupal\layout_builder\SectionStorage\SectionStorageTrait;
@@ -23,6 +24,7 @@
  */
 class LayoutBuilderEntityViewDisplay extends BaseEntityViewDisplay implements LayoutEntityDisplayInterface {
 
+  use LayoutEntityHelperTrait;
   use SectionStorageTrait;
 
   /**
@@ -274,11 +276,15 @@ public function buildMultiple(array $entities) {
    *   The sections.
    */
   protected function getRuntimeSections(FieldableEntityInterface $entity) {
-    if ($this->isOverridable() && !$entity->get('layout_builder__layout')->isEmpty()) {
-      return $entity->get('layout_builder__layout')->getSections();
-    }
+    $sections = NULL;
 
-    return $this->getSections();
+    if ($this->isOverridable()) {
+      $sections = $this->getEntitySections($entity, $this->getMode());
+    }
+    // If we don't have a section list yet (i.e., no section storage plugin
+    // was able to derive a section list from context, or this display is not
+    // overridable), use this display as the section list.
+    return $sections ?: $this->getSections();
   }
 
   /**
diff --git a/core/modules/layout_builder/src/EventSubscriber/SetInlineBlockDependency.php b/core/modules/layout_builder/src/EventSubscriber/SetInlineBlockDependency.php
index edc05f83dd..4ea6259860 100644
--- a/core/modules/layout_builder/src/EventSubscriber/SetInlineBlockDependency.php
+++ b/core/modules/layout_builder/src/EventSubscriber/SetInlineBlockDependency.php
@@ -127,7 +127,8 @@ protected function getInlineBlockDependency(BlockContentInterface $block_content
     /** @var \Drupal\layout_builder\InlineBlockUsage $usage */
     $layout_entity_storage = $this->entityTypeManager->getStorage($layout_entity_info->layout_entity_type);
     $layout_entity = $layout_entity_storage->load($layout_entity_info->layout_entity_id);
-    if ($this->isLayoutCompatibleEntity($layout_entity)) {
+    // @todo Pass 'default' until resolving https://www.drupal.org/node/3008924.
+    if ($this->isLayoutCompatibleEntity($layout_entity, 'default')) {
       if ($this->isBlockRevisionUsedInEntity($layout_entity, $block_content)) {
         return $layout_entity;
       }
@@ -149,7 +150,8 @@ protected function getInlineBlockDependency(BlockContentInterface $block_content
    *   layout entity.
    */
   protected function isBlockRevisionUsedInEntity(EntityInterface $layout_entity, BlockContentInterface $block_content) {
-    $sections_blocks_revision_ids = $this->getInlineBlockRevisionIdsInSections($this->getEntitySections($layout_entity));
+    // @todo Pass 'default' until resolving https://www.drupal.org/node/3008924.
+    $sections_blocks_revision_ids = $this->getInlineBlockRevisionIdsInSections($this->getEntitySections($layout_entity, 'default'));
     return in_array($block_content->getRevisionId(), $sections_blocks_revision_ids);
   }
 
diff --git a/core/modules/layout_builder/src/InlineBlockEntityOperations.php b/core/modules/layout_builder/src/InlineBlockEntityOperations.php
index 7e64b83cf1..3469fca493 100644
--- a/core/modules/layout_builder/src/InlineBlockEntityOperations.php
+++ b/core/modules/layout_builder/src/InlineBlockEntityOperations.php
@@ -6,7 +6,9 @@
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Entity\RevisionableInterface;
+use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
 use Drupal\layout_builder\Plugin\Block\InlineBlock;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -85,10 +87,12 @@ protected function removeUnusedForEntityOnSave(EntityInterface $entity) {
     if ($entity->isNew() || !isset($entity->original) || $entity instanceof RevisionableInterface) {
       return;
     }
-    $sections = $this->getEntitySections($entity);
+    // @todo Use 'default' until resolving https://www.drupal.org/node/3008924.
+    $view_mode = 'default';
+    $sections = $this->getEntitySections($entity, $view_mode);
     // If this is a layout override and there are no sections then it is a new
     // override.
-    if ($this->isEntityUsingFieldOverride($entity) && empty($sections)) {
+    if ($this->isEntityUsingFieldOverride($entity, $view_mode) && empty($sections)) {
       return;
     }
 
@@ -108,8 +112,10 @@ protected function removeUnusedForEntityOnSave(EntityInterface $entity) {
    *   The block content IDs that were removed.
    */
   protected function getRemovedBlockIds(EntityInterface $entity) {
-    $original_sections = $this->getEntitySections($entity->original);
-    $current_sections = $this->getEntitySections($entity);
+    // @todo Use 'default' until resolving https://www.drupal.org/node/3008924.
+    $view_mode = 'default';
+    $original_sections = $this->getEntitySections($entity->original, $view_mode);
+    $current_sections = $this->getEntitySections($entity, $view_mode);
     // Avoid un-needed conversion from revision IDs to block content IDs by
     // first determining if there are any revisions in the original that are not
     // also in the current sections.
@@ -132,11 +138,28 @@ protected function getRemovedBlockIds(EntityInterface $entity) {
    *   The parent entity.
    */
   public function handleEntityDelete(EntityInterface $entity) {
-    if ($this->isLayoutCompatibleEntity($entity)) {
+    // @todo Pass 'default' until resolving https://www.drupal.org/node/3008924.
+    if ($this->isLayoutCompatibleEntity($entity, 'default')) {
       $this->usage->removeByLayoutEntity($entity);
     }
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function isLayoutCompatibleEntity(EntityInterface $entity, $view_mode) {
+    // @todo Hardcode these checks to avoid https://www.drupal.org/node/3008943.
+    return $entity instanceof LayoutEntityDisplayInterface || $this->isEntityUsingFieldOverride($entity, $view_mode);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function isEntityUsingFieldOverride(EntityInterface $entity, $view_mode) {
+    // @todo Hardcode these checks to avoid https://www.drupal.org/node/3008943.
+    return $entity instanceof FieldableEntityInterface && $entity->hasField('layout_builder__layout');
+  }
+
   /**
    * Handles saving a parent entity.
    *
@@ -144,15 +167,17 @@ public function handleEntityDelete(EntityInterface $entity) {
    *   The parent entity.
    */
   public function handlePreSave(EntityInterface $entity) {
-    if (!$this->isLayoutCompatibleEntity($entity)) {
+    // @todo Use 'default' until resolving https://www.drupal.org/node/3008924.
+    $view_mode = 'default';
+    if (!$this->isLayoutCompatibleEntity($entity, $view_mode)) {
       return;
     }
     $duplicate_blocks = FALSE;
 
-    if ($sections = $this->getEntitySections($entity)) {
-      if ($this->isEntityUsingFieldOverride($entity)) {
+    if ($sections = $this->getEntitySections($entity, $view_mode)) {
+      if ($this->isEntityUsingFieldOverride($entity, $view_mode)) {
         if (!$entity->isNew() && isset($entity->original)) {
-          if (empty($this->getEntitySections($entity->original))) {
+          if (empty($this->getEntitySections($entity->original, $view_mode))) {
             // If there were no sections in the original entity then this is a
             // new override from a default and the blocks need to be duplicated.
             $duplicate_blocks = TRUE;
diff --git a/core/modules/layout_builder/src/LayoutEntityHelperTrait.php b/core/modules/layout_builder/src/LayoutEntityHelperTrait.php
index 9124027542..f1d86ecace 100644
--- a/core/modules/layout_builder/src/LayoutEntityHelperTrait.php
+++ b/core/modules/layout_builder/src/LayoutEntityHelperTrait.php
@@ -4,8 +4,9 @@
 
 use Drupal\Component\Plugin\DerivativeInspectionInterface;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\FieldableEntityInterface;
-use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
+use Drupal\Core\Plugin\Context\Context;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\Plugin\Context\EntityContext;
 
 /**
  * Methods to help with entities using the layout builder.
@@ -19,12 +20,14 @@ trait LayoutEntityHelperTrait {
    *
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity to check.
+   * @param string $view_mode
+   *   The view mode.
    *
    * @return bool
    *   TRUE if the entity can have a layout otherwise FALSE.
    */
-  protected function isLayoutCompatibleEntity(EntityInterface $entity) {
-    return $entity instanceof LayoutEntityDisplayInterface || $this->isEntityUsingFieldOverride($entity);
+  protected function isLayoutCompatibleEntity(EntityInterface $entity, $view_mode) {
+    return (bool) $this->getSectionStorageFromEntity($entity, $view_mode);
   }
 
   /**
@@ -47,27 +50,40 @@ protected function getInlineBlockRevisionIdsInSections(array $sections) {
     return $revision_ids;
   }
 
+  /**
+   * Gets the section storage given an entity and view mode.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity.
+   * @param string $view_mode
+   *   The view mode.
+   *
+   * @return \Drupal\layout_builder\SectionStorageInterface|null
+   *   The section storage, if it exists.
+   */
+  private function getSectionStorageFromEntity(EntityInterface $entity, $view_mode) {
+    /** @var \Drupal\layout_builder\SectionStorageInterface $storage */
+    return \Drupal::service('plugin.manager.layout_builder.section_storage')
+      ->loadFromContext([
+        'view_mode' => new Context(ContextDefinition::create('string'), $view_mode),
+        'entity' => EntityContext::fromEntity($entity),
+      ]);
+  }
+
   /**
    * Gets the sections for an entity if any.
    *
-   * @todo Replace this method with calls to the SectionStorageManagerInterface
-   * method for getting sections from an entity in
-   * https://www.drupal.org/node/2986403.
-   *
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity.
+   * @param string $view_mode
+   *   The view mode.
    *
-   * @return \Drupal\layout_builder\Section[]|null
+   * @return \Drupal\layout_builder\Section[]
    *   The entity layout sections if available.
    */
-  protected function getEntitySections(EntityInterface $entity) {
-    if ($entity instanceof LayoutEntityDisplayInterface) {
-      return $entity->getSections();
-    }
-    elseif ($this->isEntityUsingFieldOverride($entity)) {
-      return $entity->get('layout_builder__layout')->getSections();
-    }
-    return NULL;
+  protected function getEntitySections(EntityInterface $entity, $view_mode) {
+    $storage = $this->getSectionStorageFromEntity($entity, $view_mode);
+    return $storage ? $storage->getSections() : [];
   }
 
   /**
@@ -97,12 +113,15 @@ protected function getInlineBlockComponents(array $sections) {
    *
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity.
+   * @param string $view_mode
+   *   The view mode.
    *
    * @return bool
    *   TRUE if the entity is using a field for a layout override.
    */
-  protected function isEntityUsingFieldOverride(EntityInterface $entity) {
-    return $entity instanceof FieldableEntityInterface && $entity->hasField('layout_builder__layout');
+  protected function isEntityUsingFieldOverride(EntityInterface $entity, $view_mode) {
+    $storage = $this->getSectionStorageFromEntity($entity, $view_mode);
+    return $storage && $storage->getPluginId() === 'overrides';
   }
 
 }
diff --git a/core/modules/layout_builder/src/Plugin/SectionStorage/DefaultsSectionStorage.php b/core/modules/layout_builder/src/Plugin/SectionStorage/DefaultsSectionStorage.php
index d35041d03d..24c230055c 100644
--- a/core/modules/layout_builder/src/Plugin/SectionStorage/DefaultsSectionStorage.php
+++ b/core/modules/layout_builder/src/Plugin/SectionStorage/DefaultsSectionStorage.php
@@ -15,8 +15,6 @@
 use Drupal\field_ui\FieldUI;
 use Drupal\layout_builder\DefaultsSectionStorageInterface;
 use Drupal\layout_builder\Entity\LayoutBuilderSampleEntityGenerator;
-use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
-use Drupal\layout_builder\SectionListInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\Routing\RouteCollection;
 
@@ -25,6 +23,9 @@
  *
  * @SectionStorage(
  *   id = "defaults",
+ *   context = {
+ *     "entity" = @ContextDefinition("entity:entity_view_display"),
+ *   },
  * )
  *
  * @internal
@@ -90,12 +91,8 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function setSectionList(SectionListInterface $section_list) {
-    if (!$section_list instanceof LayoutEntityDisplayInterface) {
-      throw new \InvalidArgumentException('Defaults expect a display-based section list');
-    }
-
-    return parent::setSectionList($section_list);
+  protected function getSectionList() {
+    return $this->getContextValue('entity');
   }
 
   /**
@@ -237,34 +234,41 @@ protected function getEntityTypes() {
   /**
    * {@inheritdoc}
    */
-  public function extractIdFromRoute($value, $definition, $name, array $defaults) {
-    if (is_string($value) && strpos($value, '.') !== FALSE) {
-      return $value;
+  public function getContextsFromRoute($value, $definition, $name, array $defaults) {
+    $contexts = [];
+
+    if ($entity = $this->extractEntityFromRoute($value, $defaults)) {
+      $contexts['entity'] = EntityContext::fromEntity($entity);
     }
+    return $contexts;
+  }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function extractEntityFromRoute($value, array $defaults) {
     // If a bundle is not provided but a value corresponding to the bundle key
     // is, use that for the bundle value.
     if (empty($defaults['bundle']) && isset($defaults['bundle_key']) && !empty($defaults[$defaults['bundle_key']])) {
       $defaults['bundle'] = $defaults[$defaults['bundle_key']];
     }
 
-    if (!empty($defaults['entity_type_id']) && !empty($defaults['bundle']) && !empty($defaults['view_mode_name'])) {
-      return $defaults['entity_type_id'] . '.' . $defaults['bundle'] . '.' . $defaults['view_mode_name'];
+    if (is_string($value) && strpos($value, '.') !== FALSE) {
+      list($entity_type_id, $bundle, $view_mode) = explode('.', $value, 3);
     }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getSectionListFromId($id) {
-    if (strpos($id, '.') === FALSE) {
-      throw new \InvalidArgumentException(sprintf('The "%s" ID for the "%s" section storage type is invalid', $id, $this->getStorageType()));
+    elseif (!empty($defaults['entity_type_id']) && !empty($defaults['bundle']) && !empty($defaults['view_mode_name'])) {
+      $entity_type_id = $defaults['entity_type_id'];
+      $bundle = $defaults['bundle'];
+      $view_mode = $defaults['view_mode_name'];
+      $value = "$entity_type_id.$bundle.$view_mode";
+    }
+    else {
+      return NULL;
     }
 
     $storage = $this->entityTypeManager->getStorage('entity_view_display');
     // If the display does not exist, create a new one.
-    if (!$display = $storage->load($id)) {
-      list($entity_type_id, $bundle, $view_mode) = explode('.', $id, 3);
+    if (!$display = $storage->load($value)) {
       $display = $storage->create([
         'targetEntityType' => $entity_type_id,
         'bundle' => $bundle,
diff --git a/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php b/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php
index c623c5ede3..4eec93230b 100644
--- a/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php
+++ b/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php
@@ -7,14 +7,12 @@
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
-use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Plugin\Context\EntityContext;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Url;
 use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
 use Drupal\layout_builder\OverridesSectionStorageInterface;
-use Drupal\layout_builder\SectionListInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\Routing\RouteCollection;
 
@@ -23,6 +21,10 @@
  *
  * @SectionStorage(
  *   id = "overrides",
+ *   context = {
+ *     "entity" = @ContextDefinition("entity"),
+ *     "view_mode" = @ContextDefinition("string", required = FALSE),
+ *   }
  * )
  *
  * @internal
@@ -79,12 +81,8 @@ public static function create(ContainerInterface $container, array $configuratio
   /**
    * {@inheritdoc}
    */
-  public function setSectionList(SectionListInterface $section_list) {
-    if (!$section_list instanceof FieldItemListInterface) {
-      throw new \InvalidArgumentException('Overrides expect a field-based section list');
-    }
-
-    return parent::setSectionList($section_list);
+  protected function getSectionList() {
+    return $this->getEntity()->get('layout_builder__layout');
   }
 
   /**
@@ -94,7 +92,7 @@ public function setSectionList(SectionListInterface $section_list) {
    *   The entity storing the overrides.
    */
   protected function getEntity() {
-    return $this->getSectionList()->getEntity();
+    return $this->getContextValue('entity');
   }
 
   /**
@@ -108,30 +106,34 @@ public function getStorageId() {
   /**
    * {@inheritdoc}
    */
-  public function extractIdFromRoute($value, $definition, $name, array $defaults) {
+  public function getContextsFromRoute($value, $definition, $name, array $defaults) {
+    $contexts = [];
+
+    if ($entity = $this->extractEntityFromRoute($value, $defaults)) {
+      $contexts['entity'] = EntityContext::fromEntity($entity);
+    }
+    return $contexts;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function extractEntityFromRoute($value, array $defaults) {
     if (strpos($value, '.') !== FALSE) {
-      return $value;
+      list($entity_type_id, $entity_id) = explode('.', $value, 2);
     }
-
-    if (isset($defaults['entity_type_id']) && !empty($defaults[$defaults['entity_type_id']])) {
+    elseif (isset($defaults['entity_type_id']) && !empty($defaults[$defaults['entity_type_id']])) {
       $entity_type_id = $defaults['entity_type_id'];
       $entity_id = $defaults[$entity_type_id];
-      return $entity_type_id . '.' . $entity_id;
     }
-  }
+    else {
+      return NULL;
+    }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getSectionListFromId($id) {
-    if (strpos($id, '.') !== FALSE) {
-      list($entity_type_id, $entity_id) = explode('.', $id, 2);
-      $entity = $this->entityTypeManager->getStorage($entity_type_id)->load($entity_id);
-      if ($entity instanceof FieldableEntityInterface && $entity->hasField('layout_builder__layout')) {
-        return $entity->get('layout_builder__layout');
-      }
+    $entity = $this->entityTypeManager->getStorage($entity_type_id)->load($entity_id);
+    if ($entity instanceof FieldableEntityInterface && $entity->hasField('layout_builder__layout')) {
+      return $entity;
     }
-    throw new \InvalidArgumentException(sprintf('The "%s" ID for the "%s" section storage type is invalid', $id, $this->getStorageType()));
   }
 
   /**
diff --git a/core/modules/layout_builder/src/Plugin/SectionStorage/SectionStorageBase.php b/core/modules/layout_builder/src/Plugin/SectionStorage/SectionStorageBase.php
index c419060c45..8e8178355b 100644
--- a/core/modules/layout_builder/src/Plugin/SectionStorage/SectionStorageBase.php
+++ b/core/modules/layout_builder/src/Plugin/SectionStorage/SectionStorageBase.php
@@ -2,10 +2,9 @@
 
 namespace Drupal\layout_builder\Plugin\SectionStorage;
 
-use Drupal\Core\Plugin\PluginBase;
+use Drupal\Core\Plugin\ContextAwarePluginBase;
 use Drupal\layout_builder\Routing\LayoutBuilderRoutesTrait;
 use Drupal\layout_builder\Section;
-use Drupal\layout_builder\SectionListInterface;
 use Drupal\layout_builder\SectionStorageInterface;
 
 /**
@@ -16,40 +15,17 @@
  *   experimental modules and development releases of contributed modules.
  *   See https://www.drupal.org/core/experimental for more information.
  */
-abstract class SectionStorageBase extends PluginBase implements SectionStorageInterface {
+abstract class SectionStorageBase extends ContextAwarePluginBase implements SectionStorageInterface {
 
   use LayoutBuilderRoutesTrait;
 
-  /**
-   * The section storage instance.
-   *
-   * @var \Drupal\layout_builder\SectionListInterface|null
-   */
-  protected $sectionList;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setSectionList(SectionListInterface $section_list) {
-    $this->sectionList = $section_list;
-    return $this;
-  }
-
   /**
    * Gets the section list.
    *
    * @return \Drupal\layout_builder\SectionListInterface
    *   The section list.
-   *
-   * @throws \RuntimeException
-   *   Thrown if ::setSectionList() is not called first.
    */
-  protected function getSectionList() {
-    if (!$this->sectionList) {
-      throw new \RuntimeException(sprintf('%s::setSectionList() must be called first', static::class));
-    }
-    return $this->sectionList;
-  }
+  abstract protected function getSectionList();
 
   /**
    * {@inheritdoc}
@@ -103,4 +79,22 @@ public function removeSection($delta) {
     return $this;
   }
 
+  /**
+   * {@inheritdoc}
+   *
+   * @todo Remove after https://www.drupal.org/project/drupal/issues/2982626.
+   */
+  public function getContextDefinition($name) {
+    return $this->getPluginDefinition()->getContextDefinition($name);
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @todo Remove after https://www.drupal.org/project/drupal/issues/2982626.
+   */
+  public function getContextDefinitions() {
+    return $this->getPluginDefinition()->getContextDefinitions();
+  }
+
 }
diff --git a/core/modules/layout_builder/src/SectionStorage/SectionStorageDefinition.php b/core/modules/layout_builder/src/SectionStorage/SectionStorageDefinition.php
index 61b975a471..267a499aff 100644
--- a/core/modules/layout_builder/src/SectionStorage/SectionStorageDefinition.php
+++ b/core/modules/layout_builder/src/SectionStorage/SectionStorageDefinition.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\layout_builder\SectionStorage;
 
+use Drupal\Component\Plugin\Definition\ContextAwarePluginDefinitionInterface;
+use Drupal\Component\Plugin\Definition\ContextAwarePluginDefinitionTrait;
 use Drupal\Component\Plugin\Definition\PluginDefinition;
 
 /**
@@ -12,7 +14,16 @@
  *   experimental modules and development releases of contributed modules.
  *   See https://www.drupal.org/core/experimental for more information.
  */
-class SectionStorageDefinition extends PluginDefinition {
+class SectionStorageDefinition extends PluginDefinition implements ContextAwarePluginDefinitionInterface {
+
+  use ContextAwarePluginDefinitionTrait;
+
+  /**
+   * The plugin weight.
+   *
+   * @var int
+   */
+  protected $weight = 0;
 
   /**
    * Any additional properties and values.
@@ -28,6 +39,16 @@ class SectionStorageDefinition extends PluginDefinition {
    *   An array of values from the annotation.
    */
   public function __construct(array $definition = []) {
+    // If there are context definitions in the plugin definition, they should
+    // be added to this object using ::addContextDefinition() so that they can
+    // be manipulated using other ContextAwarePluginDefinitionInterface methods.
+    if (isset($definition['context'])) {
+      foreach ($definition['context'] as $name => $context_definition) {
+        $this->addContextDefinition($name, $context_definition);
+      }
+      unset($definition['context']);
+    }
+
     foreach ($definition as $property => $value) {
       $this->set($property, $value);
     }
@@ -72,4 +93,14 @@ public function set($property, $value) {
     return $this;
   }
 
+  /**
+   * Returns the plugin weight.
+   *
+   * @return int
+   *   The plugin weight.
+   */
+  public function getWeight() {
+    return $this->weight;
+  }
+
 }
diff --git a/core/modules/layout_builder/src/SectionStorage/SectionStorageManager.php b/core/modules/layout_builder/src/SectionStorage/SectionStorageManager.php
index 18147cd1d8..f92929c336 100644
--- a/core/modules/layout_builder/src/SectionStorage/SectionStorageManager.php
+++ b/core/modules/layout_builder/src/SectionStorage/SectionStorageManager.php
@@ -2,8 +2,10 @@
 
 namespace Drupal\layout_builder\SectionStorage;
 
+use Drupal\Component\Plugin\Exception\ContextException;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\Context\ContextAwarePluginManagerTrait;
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\layout_builder\Annotation\SectionStorage;
 use Drupal\layout_builder\SectionStorageInterface;
@@ -18,6 +20,8 @@
  */
 class SectionStorageManager extends DefaultPluginManager implements SectionStorageManagerInterface {
 
+  use ContextAwarePluginManagerTrait;
+
   /**
    * Constructs a new SectionStorageManager object.
    *
@@ -36,6 +40,21 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
     $this->setCacheBackend($cache_backend, 'layout_builder_section_storage_plugins');
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function findDefinitions() {
+    $definitions = parent::findDefinitions();
+
+    // Sort the definitions before they are cached.
+    $weights = array_map(function (SectionStorageDefinition $definition) {
+      return $definition->getWeight();
+    }, $definitions);
+    $ids = array_keys($definitions);
+    array_multisort($weights, $ids, $definitions);
+    return $definitions;
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -46,26 +65,46 @@ public function loadEmpty($id) {
   /**
    * {@inheritdoc}
    */
-  public function loadFromStorageId($type, $id) {
-    /** @var \Drupal\layout_builder\SectionStorageInterface $plugin */
-    $plugin = $this->createInstance($type);
-    return $plugin->setSectionList($plugin->getSectionListFromId($id));
+  public function loadFromContext(array $contexts) {
+    $storage_types = array_keys($this->getDefinitionsForContexts($contexts));
+
+    foreach ($storage_types as $type) {
+      $plugin = $this->loadWithContextsApplied($type, $contexts);
+      if ($plugin && $plugin->access('load')) {
+        return $plugin;
+      }
+    }
+    return NULL;
   }
 
   /**
    * {@inheritdoc}
    */
   public function loadFromRoute($type, $value, $definition, $name, array $defaults) {
-    /** @var \Drupal\layout_builder\SectionStorageInterface $plugin */
-    $plugin = $this->createInstance($type);
-    if ($id = $plugin->extractIdFromRoute($value, $definition, $name, $defaults)) {
-      try {
-        return $plugin->setSectionList($plugin->getSectionListFromId($id));
-      }
-      catch (\InvalidArgumentException $e) {
-        // Intentionally empty.
-      }
+    $contexts = $this->loadEmpty($type)->getContextsFromRoute($value, $definition, $name, $defaults);
+    return $this->loadWithContextsApplied($type, $contexts);
+  }
+
+  /**
+   * Loads a section storage with the provided contexts applied.
+   *
+   * @param string $type
+   *   The section storage type.
+   * @param \Drupal\Component\Plugin\Context\ContextInterface[] $contexts
+   *   The contexts available for this storage to use.
+   *
+   * @return \Drupal\layout_builder\SectionStorageInterface|null
+   *   The section storage.
+   */
+  protected function loadWithContextsApplied($type, array $contexts) {
+    $plugin = $this->loadEmpty($type);
+    try {
+      $this->contextHandler()->applyContextMapping($plugin, $contexts);
     }
+    catch (ContextException $e) {
+      return NULL;
+    }
+    return $plugin;
   }
 
 }
diff --git a/core/modules/layout_builder/src/SectionStorage/SectionStorageManagerInterface.php b/core/modules/layout_builder/src/SectionStorage/SectionStorageManagerInterface.php
index 3b269fcbba..b7627e9a4a 100644
--- a/core/modules/layout_builder/src/SectionStorage/SectionStorageManagerInterface.php
+++ b/core/modules/layout_builder/src/SectionStorage/SectionStorageManagerInterface.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\layout_builder\SectionStorage;
 
-use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Core\Plugin\Context\ContextAwarePluginManagerInterface;
 
 /**
  * Provides the interface for a plugin manager of section storage types.
@@ -12,7 +12,7 @@
  *   experimental modules and development releases of contributed modules.
  *   See https://www.drupal.org/core/experimental for more information.
  */
-interface SectionStorageManagerInterface extends DiscoveryInterface {
+interface SectionStorageManagerInterface extends ContextAwarePluginManagerInterface {
 
   /**
    * Loads a section storage with no associated section list.
@@ -26,20 +26,15 @@ interface SectionStorageManagerInterface extends DiscoveryInterface {
   public function loadEmpty($id);
 
   /**
-   * Loads a section storage populated with an existing section list.
+   * Loads a section storage populated with a section list derived from context.
    *
-   * @param string $type
-   *   The section storage type.
-   * @param string $id
-   *   The section list ID.
+   * @param \Drupal\Component\Plugin\Context\ContextInterface[] $contexts
+   *   The contexts which should be used to determine which storage to load.
    *
-   * @return \Drupal\layout_builder\SectionStorageInterface
-   *   The section storage.
-   *
-   * @throws \InvalidArgumentException
-   *   Thrown if the ID is invalid.
+   * @return \Drupal\layout_builder\SectionStorageInterface|null
+   *   The section storage if one matched all contexts, or NULL otherwise.
    */
-  public function loadFromStorageId($type, $id);
+  public function loadFromContext(array $contexts);
 
   /**
    * Loads a section storage populated with a section list derived from a route.
diff --git a/core/modules/layout_builder/src/SectionStorageInterface.php b/core/modules/layout_builder/src/SectionStorageInterface.php
index 90ce9072fd..bf078cac98 100644
--- a/core/modules/layout_builder/src/SectionStorageInterface.php
+++ b/core/modules/layout_builder/src/SectionStorageInterface.php
@@ -2,8 +2,8 @@
 
 namespace Drupal\layout_builder;
 
-use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\Core\Access\AccessibleInterface;
+use Drupal\Core\Plugin\ContextAwarePluginInterface;
 use Symfony\Component\Routing\RouteCollection;
 
 /**
@@ -14,7 +14,7 @@
  *   experimental modules and development releases of contributed modules.
  *   See https://www.drupal.org/core/experimental for more information.
  */
-interface SectionStorageInterface extends SectionListInterface, PluginInspectionInterface, AccessibleInterface {
+interface SectionStorageInterface extends SectionListInterface, ContextAwarePluginInterface, AccessibleInterface {
 
   /**
    * Returns an identifier for this storage.
@@ -34,36 +34,6 @@ public function getStorageId();
    */
   public function getStorageType();
 
-  /**
-   * Sets the section list on the storage.
-   *
-   * @param \Drupal\layout_builder\SectionListInterface $section_list
-   *   The section list.
-   *
-   * @return $this
-   *
-   * @internal
-   *   This should only be called during section storage instantiation.
-   */
-  public function setSectionList(SectionListInterface $section_list);
-
-  /**
-   * Derives the section list from the storage ID.
-   *
-   * @param string $id
-   *   The storage ID, see ::getStorageId().
-   *
-   * @return \Drupal\layout_builder\SectionListInterface
-   *   The section list.
-   *
-   * @throws \InvalidArgumentException
-   *   Thrown if the ID is invalid.
-   *
-   * @internal
-   *   This should only be called during section storage instantiation.
-   */
-  public function getSectionListFromId($id);
-
   /**
    * Provides the routes needed for Layout Builder UI.
    *
@@ -99,7 +69,7 @@ public function getRedirectUrl();
   public function getLayoutBuilderUrl($rel = 'view');
 
   /**
-   * Configures the plugin based on route values.
+   * Derives the required plugin contexts from route values.
    *
    * @param mixed $value
    *   The raw value.
@@ -110,21 +80,10 @@ public function getLayoutBuilderUrl($rel = 'view');
    * @param array $defaults
    *   The route defaults array.
    *
-   * @return string|null
-   *   The section storage ID if it could be extracted, NULL otherwise.
-   *
-   * @internal
-   *   This should only be called during section storage instantiation.
-   */
-  public function extractIdFromRoute($value, $definition, $name, array $defaults);
-
-  /**
-   * Provides any available contexts for the object using the sections.
-   *
    * @return \Drupal\Core\Plugin\Context\ContextInterface[]
-   *   The array of context objects.
+   *   The required plugin contexts.
    */
-  public function getContexts();
+  public function getContextsFromRoute($value, $definition, $name, array $defaults);
 
   /**
    * Gets the label for the object using the sections.
diff --git a/core/modules/layout_builder/tests/modules/layout_builder_test/layout_builder_test.module b/core/modules/layout_builder/tests/modules/layout_builder_test/layout_builder_test.module
index e7d310a6cb..8e9991f8cd 100644
--- a/core/modules/layout_builder/tests/modules/layout_builder_test/layout_builder_test.module
+++ b/core/modules/layout_builder/tests/modules/layout_builder_test/layout_builder_test.module
@@ -7,6 +7,7 @@
 
 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\layout_builder_test\Plugin\SectionStorage\TestOverridesSectionStorage;
 
 /**
  * Implements hook_plugin_filter_TYPE__CONSUMER_alter().
@@ -58,3 +59,15 @@ function layout_builder_test_node_view(array &$build, EntityInterface $entity, E
     ];
   }
 }
+
+/**
+ * Implements hook_layout_builder_section_storage_alter().
+ */
+function layout_builder_test_layout_builder_section_storage_alter(array &$storages) {
+  /** @var \Drupal\layout_builder\SectionStorage\SectionStorageDefinition[] $storages */
+  $storages['overrides']->setClass(TestOverridesSectionStorage::class);
+  $storages['overrides']->set('weight', -10);
+
+  $storages['overrides_heavy'] = clone $storages['overrides'];
+  $storages['overrides_heavy']->set('weight', -8);
+}
diff --git a/core/modules/layout_builder/tests/modules/layout_builder_test/src/Plugin/SectionStorage/TestOverridesSectionStorage.php b/core/modules/layout_builder/tests/modules/layout_builder_test/src/Plugin/SectionStorage/TestOverridesSectionStorage.php
new file mode 100644
index 0000000000..d4fd459343
--- /dev/null
+++ b/core/modules/layout_builder/tests/modules/layout_builder_test/src/Plugin/SectionStorage/TestOverridesSectionStorage.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Drupal\layout_builder_test\Plugin\SectionStorage;
+
+use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage;
+
+/**
+ * Provides a test override of section storage.
+ */
+class TestOverridesSectionStorage extends OverridesSectionStorage {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getSectionList() {
+    \Drupal::state()->set('layout_builder_test_storage', [
+      $this->getPluginDefinition()->get('weight'),
+      $this->getContextValue('view_mode'),
+    ]);
+    return parent::getSectionList();
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php
index 2d22829752..de05d39bf1 100644
--- a/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php
+++ b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php
@@ -557,4 +557,31 @@ public function testBlockPlaceholder() {
     $assert_session->pageTextContains($block_content);
   }
 
+  /**
+   * Tests that section loading is delegated to plugins during rendering.
+   */
+  public function testRenderByContextualPluginDelegate() {
+    $state_key = 'layout_builder_test_storage';
+    /** @var \Drupal\Core\State\StateInterface $state */
+    $state = $this->container->get('state');
+
+    $this->drupalGet('node/1');
+    $this->assertEmpty($state->get($state_key));
+
+    entity_get_display('node', 'bundle_with_section_field', 'full')
+      ->enableLayoutBuilder()
+      ->setOverridable()
+      ->save();
+
+    $this->getSession()->reload();
+    $state->resetCache();
+    // During layout rendering, the storage plugin used for testing will set the
+    // state key to an array containing the plugin weight and view mode, which
+    // proves that the plugin matched the appropriate contexts and was actually
+    // used to render the layout.
+    list ($weight, $view_mode) = $state->get($state_key);
+    $this->assertSame(-10, $weight);
+    $this->assertSame('full', $view_mode);
+  }
+
 }
diff --git a/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php b/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php
index d30917a446..726d62dcab 100644
--- a/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php
@@ -8,6 +8,7 @@
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
+use Drupal\Core\Plugin\Context\ContextInterface;
 use Drupal\layout_builder\Entity\LayoutBuilderSampleEntityGenerator;
 use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
 use Drupal\layout_builder\Plugin\SectionStorage\DefaultsSectionStorage;
@@ -61,8 +62,12 @@ protected function setUp() {
   public function testThirdPartySettings() {
     // Set an initial value on the section list.
     $section_list = $this->prophesize(LayoutEntityDisplayInterface::class);
+
+    $context = $this->prophesize(ContextInterface::class);
+    $context->getContextValue()->willReturn($section_list->reveal());
+    $this->plugin->setContext('entity', $context->reveal());
+
     $section_list->getThirdPartySetting('the_module', 'the_key', NULL)->willReturn('value 1');
-    $this->plugin->setSectionList($section_list->reveal());
 
     // The plugin returns the initial value.
     $this->assertSame('value 1', $this->plugin->getThirdPartySetting('the_module', 'the_key'));
@@ -79,58 +84,11 @@ public function testThirdPartySettings() {
   }
 
   /**
-   * @covers ::extractIdFromRoute
+   * @covers ::extractEntityFromRoute
    *
-   * @dataProvider providerTestExtractIdFromRoute
+   * @dataProvider providerTestExtractEntityFromRoute
    */
-  public function testExtractIdFromRoute($expected, $value, array $defaults) {
-    $result = $this->plugin->extractIdFromRoute($value, [], 'the_parameter_name', $defaults);
-    $this->assertSame($expected, $result);
-  }
-
-  /**
-   * Provides data for ::testExtractIdFromRoute().
-   */
-  public function providerTestExtractIdFromRoute() {
-    $data = [];
-    $data['with value'] = [
-      'foo.bar.baz',
-      'foo.bar.baz',
-      [],
-    ];
-    $data['empty value, without bundle'] = [
-      'my_entity_type.bundle_name.default',
-      '',
-      [
-        'entity_type_id' => 'my_entity_type',
-        'view_mode_name' => 'default',
-        'bundle_key' => 'my_bundle',
-        'my_bundle' => 'bundle_name',
-      ],
-    ];
-    $data['empty value, with bundle'] = [
-      'my_entity_type.bundle_name.default',
-      '',
-      [
-        'entity_type_id' => 'my_entity_type',
-        'view_mode_name' => 'default',
-        'bundle' => 'bundle_name',
-      ],
-    ];
-    $data['without value, empty defaults'] = [
-      NULL,
-      '',
-      [],
-    ];
-    return $data;
-  }
-
-  /**
-   * @covers ::getSectionListFromId
-   *
-   * @dataProvider providerTestGetSectionListFromId
-   */
-  public function testGetSectionListFromId($success, $expected_entity_id, $value) {
+  public function testExtractEntityFromRoute($success, $expected_entity_id, $value, array $defaults = []) {
     if ($expected_entity_id) {
       $entity_storage = $this->prophesize(EntityStorageInterface::class);
       $entity_storage->load($expected_entity_id)->willReturn('the_return_value');
@@ -143,26 +101,48 @@ public function testGetSectionListFromId($success, $expected_entity_id, $value)
       $this->entityTypeManager->getStorage('entity_view_display')->shouldNotBeCalled();
     }
 
-    if (!$success) {
-      $this->setExpectedException(\InvalidArgumentException::class);
-    }
-
-    $result = $this->plugin->getSectionListFromId($value);
+    $method = new \ReflectionMethod($this->plugin, 'extractEntityFromRoute');
+    $method->setAccessible(TRUE);
+    $result = $method->invoke($this->plugin, $value, $defaults);
     if ($success) {
       $this->assertEquals('the_return_value', $result);
     }
+    else {
+      $this->assertNull($result);
+    }
   }
 
   /**
-   * Provides data for ::testGetSectionListFromId().
+   * Provides data for ::testExtractEntityFromRoute().
    */
-  public function providerTestGetSectionListFromId() {
+  public function providerTestExtractEntityFromRoute() {
     $data = [];
     $data['with value'] = [
       TRUE,
       'foo.bar.baz',
       'foo.bar.baz',
     ];
+    $data['empty value, without bundle'] = [
+      TRUE,
+      'my_entity_type.bundle_name.default',
+      '',
+      [
+        'entity_type_id' => 'my_entity_type',
+        'view_mode_name' => 'default',
+        'bundle_key' => 'my_bundle',
+        'my_bundle' => 'bundle_name',
+      ],
+    ];
+    $data['empty value, with bundle'] = [
+      TRUE,
+      'my_entity_type.bundle_name.default',
+      '',
+      [
+        'entity_type_id' => 'my_entity_type',
+        'view_mode_name' => 'default',
+        'bundle' => 'bundle_name',
+      ],
+    ];
     $data['without value, empty defaults'] = [
       FALSE,
       NULL,
@@ -172,9 +152,9 @@ public function providerTestGetSectionListFromId() {
   }
 
   /**
-   * @covers ::getSectionListFromId
+   * @covers ::extractEntityFromRoute
    */
-  public function testGetSectionListFromIdCreate() {
+  public function testExtractEntityFromRouteCreate() {
     $expected = 'the_return_value';
     $value = 'foo.bar.baz';
     $expected_create_values = [
@@ -190,7 +170,9 @@ public function testGetSectionListFromIdCreate() {
     $this->entityTypeManager->getDefinition('entity_view_display')->willReturn(new EntityType(['id' => 'entity_view_display']));
     $this->entityTypeManager->getStorage('entity_view_display')->willReturn($entity_storage->reveal());
 
-    $result = $this->plugin->getSectionListFromId($value);
+    $method = new \ReflectionMethod($this->plugin, 'extractEntityFromRoute');
+    $method->setAccessible(TRUE);
+    $result = $method->invoke($this->plugin, $value, []);
     $this->assertSame($expected, $result);
   }
 
diff --git a/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php b/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
index 110ec2021e..d3574be6dd 100644
--- a/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
@@ -60,87 +60,42 @@ protected function setUp() {
   }
 
   /**
-   * @covers ::extractIdFromRoute
+   * @covers ::extractEntityFromRoute
    *
-   * @dataProvider providerTestExtractIdFromRoute
+   * @dataProvider providerTestExtractEntityFromRoute
    */
-  public function testExtractIdFromRoute($expected, $value, array $defaults) {
-    $result = $this->plugin->extractIdFromRoute($value, [], 'the_parameter_name', $defaults);
-    $this->assertSame($expected, $result);
-  }
-
-  /**
-   * Provides data for ::testExtractIdFromRoute().
-   */
-  public function providerTestExtractIdFromRoute() {
-    $data = [];
-    $data['with value, with layout'] = [
-      'my_entity_type.entity_with_layout',
-      'my_entity_type.entity_with_layout',
-      [],
-    ];
-    $data['with value, without layout'] = [
-      NULL,
-      'my_entity_type',
-      [],
-    ];
-    $data['empty value, populated defaults'] = [
-      'my_entity_type.entity_with_layout',
-      '',
-      [
-        'entity_type_id' => 'my_entity_type',
-        'my_entity_type' => 'entity_with_layout',
-      ],
-    ];
-    $data['empty value, empty defaults'] = [
-      NULL,
-      '',
-      [],
-    ];
-    return $data;
-  }
-
-  /**
-   * @covers ::getSectionListFromId
-   *
-   * @dataProvider providerTestGetSectionListFromId
-   */
-  public function testGetSectionListFromId($success, $expected_entity_type_id, $id) {
-    $defaults['the_parameter_name'] = $id;
-
+  public function testExtractEntityFromRoute($success, $expected_entity_type_id, $value, array $defaults = []) {
     if ($expected_entity_type_id) {
       $entity_storage = $this->prophesize(EntityStorageInterface::class);
 
       $entity_without_layout = $this->prophesize(FieldableEntityInterface::class);
       $entity_without_layout->hasField('layout_builder__layout')->willReturn(FALSE);
-      $entity_without_layout->get('layout_builder__layout')->shouldNotBeCalled();
       $entity_storage->load('entity_without_layout')->willReturn($entity_without_layout->reveal());
 
       $entity_with_layout = $this->prophesize(FieldableEntityInterface::class);
       $entity_with_layout->hasField('layout_builder__layout')->willReturn(TRUE);
-      $entity_with_layout->get('layout_builder__layout')->willReturn('the_return_value');
       $entity_storage->load('entity_with_layout')->willReturn($entity_with_layout->reveal());
-
       $this->entityTypeManager->getStorage($expected_entity_type_id)->willReturn($entity_storage->reveal());
     }
     else {
       $this->entityTypeManager->getStorage(Argument::any())->shouldNotBeCalled();
     }
 
-    if (!$success) {
-      $this->setExpectedException(\InvalidArgumentException::class);
-    }
-
-    $result = $this->plugin->getSectionListFromId($id);
+    $method = new \ReflectionMethod($this->plugin, 'extractEntityFromRoute');
+    $method->setAccessible(TRUE);
+    $result = $method->invoke($this->plugin, $value, $defaults);
     if ($success) {
-      $this->assertEquals('the_return_value', $result);
+      $this->assertInstanceOf(FieldableEntityInterface::class, $result);
+    }
+    else {
+      $this->assertNull($result);
     }
   }
 
   /**
-   * Provides data for ::testGetSectionListFromId().
+   * Provides data for ::testExtractEntityFromRoute().
    */
-  public function providerTestGetSectionListFromId() {
+  public function providerTestExtractEntityFromRoute() {
     $data = [];
     $data['with value, with layout'] = [
       TRUE,
@@ -152,6 +107,15 @@ public function providerTestGetSectionListFromId() {
       'my_entity_type',
       'my_entity_type.entity_without_layout',
     ];
+    $data['empty value, populated defaults'] = [
+      TRUE,
+      'my_entity_type',
+      '',
+      [
+        'entity_type_id' => 'my_entity_type',
+        'my_entity_type' => 'entity_with_layout',
+      ],
+    ];
     $data['empty value, empty defaults'] = [
       FALSE,
       NULL,
diff --git a/core/modules/layout_builder/tests/src/Unit/SectionStorageManagerTest.php b/core/modules/layout_builder/tests/src/Unit/SectionStorageManagerTest.php
index 392cd8939e..dce906aa6d 100644
--- a/core/modules/layout_builder/tests/src/Unit/SectionStorageManagerTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/SectionStorageManagerTest.php
@@ -2,10 +2,17 @@
 
 namespace Drupal\Tests\layout_builder\Unit;
 
+use Drupal\Component\Plugin\Context\ContextInterface;
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Plugin\Exception\ContextException;
 use Drupal\Component\Plugin\Factory\FactoryInterface;
 use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\layout_builder\SectionListInterface;
+use Drupal\Core\Plugin\Context\Context;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\Plugin\Context\ContextHandlerInterface;
+use Drupal\layout_builder\SectionStorage\SectionStorageDefinition;
 use Drupal\layout_builder\SectionStorage\SectionStorageManager;
 use Drupal\layout_builder\SectionStorageInterface;
 use Drupal\Tests\UnitTestCase;
@@ -20,16 +27,30 @@ class SectionStorageManagerTest extends UnitTestCase {
   /**
    * The section storage manager.
    *
-   * @var \Drupal\layout_builder\SectionStorage\SectionStorageManager
+   * @var \Drupal\Tests\layout_builder\Unit\TestSectionStorageManager
    */
   protected $manager;
 
   /**
-   * The plugin.
+   * The plugin discovery.
    *
-   * @var \Drupal\layout_builder\SectionStorageInterface
+   * @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface
    */
-  protected $plugin;
+  protected $discovery;
+
+  /**
+   * The plugin factory.
+   *
+   * @var \Drupal\Component\Plugin\Factory\FactoryInterface
+   */
+  protected $factory;
+
+  /**
+   * The context handler.
+   *
+   * @var \Drupal\Core\Plugin\Context\ContextHandlerInterface
+   */
+  protected $contextHandler;
 
   /**
    * {@inheritdoc}
@@ -37,64 +58,150 @@ class SectionStorageManagerTest extends UnitTestCase {
   protected function setUp() {
     parent::setUp();
 
+    $this->discovery = $this->prophesize(DiscoveryInterface::class);
+    $this->factory = $this->prophesize(FactoryInterface::class);
     $cache = $this->prophesize(CacheBackendInterface::class);
     $module_handler = $this->prophesize(ModuleHandlerInterface::class);
-    $this->manager = new SectionStorageManager(new \ArrayObject(), $cache->reveal(), $module_handler->reveal());
+    $this->manager = new TestSectionStorageManager($this->discovery->reveal(), $this->factory->reveal(), $cache->reveal(), $module_handler->reveal());
 
-    $this->plugin = $this->prophesize(SectionStorageInterface::class);
+    $this->contextHandler = $this->prophesize(ContextHandlerInterface::class);
+    $container = new ContainerBuilder();
+    $container->set('context.handler', $this->contextHandler->reveal());
+    \Drupal::setContainer($container);
 
-    $factory = $this->prophesize(FactoryInterface::class);
-    $factory->createInstance('the_plugin_id', [])->willReturn($this->plugin->reveal());
-    $reflection_property = new \ReflectionProperty($this->manager, 'factory');
-    $reflection_property->setAccessible(TRUE);
-    $reflection_property->setValue($this->manager, $factory->reveal());
   }
 
   /**
    * @covers ::loadEmpty
    */
   public function testLoadEmpty() {
+    $plugin = $this->prophesize(SectionStorageInterface::class);
+    $this->factory->createInstance('the_plugin_id', [])->willReturn($plugin->reveal());
+
     $result = $this->manager->loadEmpty('the_plugin_id');
-    $this->assertInstanceOf(SectionStorageInterface::class, $result);
-  }
-
-  /**
-   * @covers ::loadFromStorageId
-   */
-  public function testLoadFromStorageId() {
-    $section_list = $this->prophesize(SectionListInterface::class);
-    $this->plugin->setSectionList($section_list->reveal())->will(function () {
-      return $this;
-    });
-    $this->plugin->getSectionListFromId('the_storage_id')->willReturn($section_list->reveal());
-
-    $result = $this->manager->loadFromStorageId('the_plugin_id', 'the_storage_id');
-    $this->assertInstanceOf(SectionStorageInterface::class, $result);
+    $this->assertSame($plugin->reveal(), $result);
   }
 
   /**
    * @covers ::loadFromRoute
    */
   public function testLoadFromRoute() {
-    $section_list = $this->prophesize(SectionListInterface::class);
-    $this->plugin->extractIdFromRoute('the_value', [], 'the_parameter_name', [])->willReturn('the_storage_id');
-    $this->plugin->getSectionListFromId('the_storage_id')->willReturn($section_list->reveal());
-    $this->plugin->setSectionList($section_list->reveal())->will(function () {
-      return $this;
-    });
+    $plugin = $this->prophesize(SectionStorageInterface::class);
+    $this->factory->createInstance('the_plugin_id', [])->willReturn($plugin->reveal());
+
+    $contexts = [
+      'the_context' => $this->prophesize(ContextInterface::class)->reveal(),
+    ];
+    $plugin->getContextsFromRoute('the_value', [], 'the_parameter_name', [])->willReturn($contexts);
+    $plugin->access('load')->willReturn(TRUE);
 
     $result = $this->manager->loadFromRoute('the_plugin_id', 'the_value', [], 'the_parameter_name', []);
-    $this->assertInstanceOf(SectionStorageInterface::class, $result);
+    $this->assertSame($plugin->reveal(), $result);
   }
 
   /**
    * @covers ::loadFromRoute
    */
   public function testLoadFromRouteNull() {
-    $this->plugin->extractIdFromRoute('the_value', [], 'the_parameter_name', ['_route' => 'the_route_name'])->willReturn(NULL);
+    $plugin = $this->prophesize(SectionStorageInterface::class);
+    $this->factory->createInstance('the_plugin_id', [])->willReturn($plugin->reveal());
+
+    $plugin->getContextsFromRoute('the_value', [], 'the_parameter_name', ['_route' => 'the_route_name'])->willReturn([]);
+    $this->contextHandler->applyContextMapping($plugin, [])->willThrow(new ContextException());
+    $plugin->access('load')->shouldNotBeCalled();
 
     $result = $this->manager->loadFromRoute('the_plugin_id', 'the_value', [], 'the_parameter_name', ['_route' => 'the_route_name']);
     $this->assertNull($result);
   }
 
+  /**
+   * @covers ::findDefinitions
+   */
+  public function testFindDefinitions() {
+    $this->discovery->getDefinitions()->willReturn([
+      'plugin1' => new SectionStorageDefinition(),
+      'plugin2' => new SectionStorageDefinition(['weight' => -5]),
+      'plugin3' => new SectionStorageDefinition(['weight' => -5]),
+      'plugin4' => new SectionStorageDefinition(['weight' => 10]),
+    ]);
+
+    $expected = [
+      'plugin2',
+      'plugin3',
+      'plugin1',
+      'plugin4',
+    ];
+    $result = $this->manager->getDefinitions();
+    $this->assertSame($expected, array_keys($result));
+  }
+
+  /**
+   * @covers ::loadFromContext
+   *
+   * @dataProvider providerTestLoadFromContext
+   */
+  public function testLoadFromContext($access) {
+    $contexts = [
+      'foo' => new Context(new ContextDefinition('foo')),
+    ];
+    $definitions = [
+      'no_access' => new SectionStorageDefinition(),
+      'missing_contexts' => new SectionStorageDefinition(),
+      'provider_access' => new SectionStorageDefinition(),
+    ];
+    $this->discovery->getDefinitions()->willReturn($definitions);
+
+    $provider_access = $this->prophesize(SectionStorageInterface::class);
+    $provider_access->access('load')->willReturn($access);
+
+    $no_access = $this->prophesize(SectionStorageInterface::class);
+    $no_access->access('load')->willReturn(FALSE);
+
+    $missing_contexts = $this->prophesize(SectionStorageInterface::class);
+
+    // Do not do any filtering based on context.
+    $this->contextHandler->filterPluginDefinitionsByContexts($contexts, $definitions)->willReturnArgument(1);
+    $this->contextHandler->applyContextMapping($no_access, $contexts)->shouldBeCalled();
+    $this->contextHandler->applyContextMapping($provider_access, $contexts)->shouldBeCalled();
+    $this->contextHandler->applyContextMapping($missing_contexts, $contexts)->willThrow(new ContextException());
+
+    $this->factory->createInstance('no_access', [])->willReturn($no_access->reveal());
+    $this->factory->createInstance('missing_contexts', [])->willReturn($missing_contexts->reveal());
+    $this->factory->createInstance('provider_access', [])->willReturn($provider_access->reveal());
+
+    $result = $this->manager->loadFromContext($contexts);
+    if ($access) {
+      $this->assertSame($provider_access->reveal(), $result);
+    }
+    else {
+      $this->assertNull($result);
+    }
+  }
+
+  /**
+   * Provides test data for ::testLoadFromContext().
+   */
+  public function providerTestLoadFromContext() {
+    $data = [];
+    $data['true'] = [TRUE];
+    $data['false'] = [FALSE];
+    return $data;
+  }
+
+}
+
+/**
+ * Provides a test manager.
+ */
+class TestSectionStorageManager extends SectionStorageManager {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(DiscoveryInterface $discovery, FactoryInterface $factory, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+    parent::__construct(new \ArrayObject(), $cache_backend, $module_handler);
+    $this->discovery = $discovery;
+    $this->factory = $factory;
+  }
+
 }
diff --git a/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionIsSatisfiedTest.php b/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionIsSatisfiedTest.php
index c93e77de9f..661ee2ee04 100644
--- a/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionIsSatisfiedTest.php
+++ b/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionIsSatisfiedTest.php
@@ -29,6 +29,7 @@ protected function setUp() {
     $namespaces = new \ArrayObject([
       'Drupal\\Core\\TypedData' => $this->root . '/core/lib/Drupal/Core/TypedData',
       'Drupal\\Core\\Validation' => $this->root . '/core/lib/Drupal/Core/Validation',
+      'Drupal\\Tests\\Core\\Plugin\\Fixtures' => $this->root . '/core/tests/Drupal/Tests/Core/Plugin/Fixtures',
     ]);
     $cache_backend = new NullBackend('cache');
     $module_handler = $this->prophesize(ModuleHandlerInterface::class);
@@ -60,6 +61,7 @@ protected function setUp() {
    *   (optional) The value to set on the context, defaults to NULL.
    *
    * @covers ::isSatisfiedBy
+   * @covers ::dataTypeMatches
    * @covers ::getSampleValues
    * @covers ::getConstraintObjects
    *
@@ -116,6 +118,16 @@ public function providerTestIsSatisfiedBy() {
       new InheritedContextDefinition('any'),
       new ContextDefinition('any'),
     ];
+    $data['specific definition, generic requirement'] = [
+      TRUE,
+      new ContextDefinition('test_data_type'),
+      new ContextDefinition('test_data_type:a_variant'),
+    ];
+    $data['generic definition, specific requirement'] = [
+      FALSE,
+      new ContextDefinition('test_data_type:a_variant'),
+      new ContextDefinition('test_data_type'),
+    ];
 
     return $data;
   }
diff --git a/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextDefinitionIsSatisfiedTest.php b/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextDefinitionIsSatisfiedTest.php
index 69adfdd271..8e9b259a4f 100644
--- a/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextDefinitionIsSatisfiedTest.php
+++ b/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextDefinitionIsSatisfiedTest.php
@@ -13,6 +13,7 @@
 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\Context\ContextDefinition;
 use Drupal\Core\Plugin\Context\EntityContext;
 use Drupal\Core\Plugin\Context\EntityContextDefinition;
 use Drupal\Core\TypedData\TypedDataManager;
@@ -95,19 +96,20 @@ protected function setUp() {
    * @param mixed $value
    *   (optional) The value to set on the context, defaults to NULL.
    */
-  protected function assertRequirementIsSatisfied($expected, EntityContextDefinition $requirement, EntityContextDefinition $definition, $value = NULL) {
+  protected function assertRequirementIsSatisfied($expected, ContextDefinition $requirement, ContextDefinition $definition, $value = NULL) {
     $context = new EntityContext($definition, $value);
     $this->assertSame($expected, $requirement->isSatisfiedBy($context));
   }
 
   /**
    * @covers ::isSatisfiedBy
+   * @covers ::dataTypeMatches
    * @covers ::getSampleValues
    * @covers ::getConstraintObjects
    *
    * @dataProvider providerTestIsSatisfiedBy
    */
-  public function testIsSatisfiedBy($expected, EntityContextDefinition $requirement, EntityContextDefinition $definition, $value = NULL) {
+  public function testIsSatisfiedBy($expected, ContextDefinition $requirement, ContextDefinition $definition, $value = NULL) {
     $entity_storage = $this->prophesize(EntityStorageInterface::class);
     $content_entity_storage = $this->prophesize(ContentEntityStorageInterface::class);
     $this->entityTypeManager->getStorage('test_config')->willReturn($entity_storage->reveal());
@@ -169,12 +171,23 @@ public function providerTestIsSatisfiedBy() {
       EntityContextDefinition::fromEntityType($config),
       EntityContextDefinition::fromEntityType($config),
     ];
+    $data['generic entity requirement, specific context'] = [
+      TRUE,
+      new ContextDefinition('entity'),
+      EntityContextDefinition::fromEntityType($config),
+    ];
+    $data['specific requirement, generic entity context'] = [
+      FALSE,
+      EntityContextDefinition::fromEntityType($content),
+      new ContextDefinition('entity'),
+    ];
 
     return $data;
   }
 
   /**
    * @covers ::isSatisfiedBy
+   * @covers ::dataTypeMatches
    * @covers ::getSampleValues
    * @covers ::getConstraintObjects
    *
@@ -271,6 +284,7 @@ public function providerTestIsSatisfiedByGenerateBundledEntity() {
 
   /**
    * @covers ::isSatisfiedBy
+   * @covers ::dataTypeMatches
    * @covers ::getSampleValues
    * @covers ::getConstraintObjects
    *
diff --git a/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextTypedDataTest.php b/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextTypedDataTest.php
new file mode 100644
index 0000000000..0595557a5b
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Plugin/Context/EntityContextTypedDataTest.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Drupal\Tests\Core\Plugin\Context;
+
+use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\Core\Plugin\Context\EntityContext;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests the interaction between entity context and typed data.
+ *
+ * @group Context
+ */
+class EntityContextTypedDataTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = ['entity_test'];
+
+  /**
+   * Tests that entity contexts wrapping a config entity can be validated.
+   */
+  public function testValidateConfigEntityContext() {
+    $display = EntityViewDisplay::create([
+      'targetEntityType' => 'entity_test',
+      'bundle' => 'entity_test',
+      'mode' => 'default',
+      'status' => TRUE,
+    ]);
+    $display->save();
+
+    $violations = EntityContext::fromEntity($display)->validate();
+    $this->assertCount(0, $violations);
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Plugin/Fixtures/Plugin/DataType/TestDataType.php b/core/tests/Drupal/Tests/Core/Plugin/Fixtures/Plugin/DataType/TestDataType.php
new file mode 100644
index 0000000000..f647238acc
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Plugin/Fixtures/Plugin/DataType/TestDataType.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Drupal\Tests\Core\Plugin\Fixtures\Plugin\DataType;
+
+use Drupal\Core\TypedData\TypedData;
+
+/**
+ * Provides a test data type.
+ *
+ * @DataType(
+ *   id = "test_data_type",
+ *   label = @Translation("Test data type"),
+ *   deriver = "Drupal\Tests\Core\Plugin\Fixtures\Plugin\DataType\TestDataTypeDeriver"
+ * )
+ */
+class TestDataType extends TypedData {
+
+  /**
+   * Required by the parent class.
+   *
+   * @var mixed
+   */
+  protected $value;
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Plugin/Fixtures/Plugin/DataType/TestDataTypeDeriver.php b/core/tests/Drupal/Tests/Core/Plugin/Fixtures/Plugin/DataType/TestDataTypeDeriver.php
new file mode 100644
index 0000000000..b7328270b2
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Plugin/Fixtures/Plugin/DataType/TestDataTypeDeriver.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Drupal\Tests\Core\Plugin\Fixtures\Plugin\DataType;
+
+use Drupal\Component\Plugin\Derivative\DeriverBase;
+
+/**
+ * Provides a deriver that returns a plugin for the bare ID and one variant.
+ */
+class TestDataTypeDeriver extends DeriverBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions($base_plugin_definition) {
+    foreach (['', 'a_variant'] as $item) {
+      $this->derivatives[$item] = $base_plugin_definition;
+      $this->derivatives[$item]['provider'] = 'core';
+    }
+    return $this->derivatives;
+  }
+
+}
