diff --git a/core/modules/layout_builder/layout_builder.module b/core/modules/layout_builder/layout_builder.module
index 48f62e98cf..dbb19bd010 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/layout_builder.routing.yml b/core/modules/layout_builder/layout_builder.routing.yml
index 3e3ee1b024..4e1b66beda 100644
--- a/core/modules/layout_builder/layout_builder.routing.yml
+++ b/core/modules/layout_builder/layout_builder.routing.yml
@@ -4,7 +4,7 @@ layout_builder.choose_section:
    _controller: '\Drupal\layout_builder\Controller\ChooseSectionController::build'
   requirements:
     _permission: 'configure any layout'
-    _layout_builder_access: 'view'
+    _layout_builder_access: 'update'
   options:
     _admin_route: TRUE
     parameters:
@@ -17,7 +17,7 @@ layout_builder.add_section:
     _controller: '\Drupal\layout_builder\Controller\AddSectionController::build'
   requirements:
     _permission: 'configure any layout'
-    _layout_builder_access: 'view'
+    _layout_builder_access: 'update'
   options:
     _admin_route: TRUE
     parameters:
@@ -34,7 +34,7 @@ layout_builder.configure_section:
     plugin_id: null
   requirements:
     _permission: 'configure any layout'
-    _layout_builder_access: 'view'
+    _layout_builder_access: 'update'
   options:
     _admin_route: TRUE
     parameters:
@@ -47,7 +47,7 @@ layout_builder.remove_section:
     _form: '\Drupal\layout_builder\Form\RemoveSectionForm'
   requirements:
     _permission: 'configure any layout'
-    _layout_builder_access: 'view'
+    _layout_builder_access: 'update'
   options:
     _admin_route: TRUE
     parameters:
@@ -60,7 +60,7 @@ layout_builder.choose_block:
     _controller: '\Drupal\layout_builder\Controller\ChooseBlockController::build'
   requirements:
     _permission: 'configure any layout'
-    _layout_builder_access: 'view'
+    _layout_builder_access: 'update'
   options:
     _admin_route: TRUE
     parameters:
@@ -73,7 +73,7 @@ layout_builder.add_block:
     _form: '\Drupal\layout_builder\Form\AddBlockForm'
   requirements:
     _permission: 'configure any layout'
-    _layout_builder_access: 'view'
+    _layout_builder_access: 'update'
   options:
     _admin_route: TRUE
     parameters:
@@ -99,7 +99,7 @@ layout_builder.update_block:
     _form: '\Drupal\layout_builder\Form\UpdateBlockForm'
   requirements:
     _permission: 'configure any layout'
-    _layout_builder_access: 'view'
+    _layout_builder_access: 'update'
   options:
     _admin_route: TRUE
     parameters:
@@ -112,7 +112,7 @@ layout_builder.remove_block:
     _form: '\Drupal\layout_builder\Form\RemoveBlockForm'
   requirements:
     _permission: 'configure any layout'
-    _layout_builder_access: 'view'
+    _layout_builder_access: 'update'
   options:
     _admin_route: TRUE
     parameters:
@@ -131,7 +131,7 @@ layout_builder.move_block:
     preceding_block_uuid: null
   requirements:
     _permission: 'configure any layout'
-    _layout_builder_access: 'view'
+    _layout_builder_access: 'update'
   options:
     _admin_route: TRUE
     parameters:
diff --git a/core/modules/layout_builder/layout_builder.services.yml b/core/modules/layout_builder/layout_builder.services.yml
index 56b4bf88bd..f0c517d995 100644
--- a/core/modules/layout_builder/layout_builder.services.yml
+++ b/core/modules/layout_builder/layout_builder.services.yml
@@ -13,6 +13,7 @@ services:
   plugin.manager.layout_builder.section_storage:
     class: Drupal\layout_builder\SectionStorage\SectionStorageManager
     parent: default_plugin_manager
+    arguments: ['@context.handler']
   layout_builder.routes:
     class: Drupal\layout_builder\Routing\LayoutBuilderRoutes
     arguments: ['@plugin.manager.layout_builder.section_storage']
diff --git a/core/modules/layout_builder/src/Annotation/SectionStorage.php b/core/modules/layout_builder/src/Annotation/SectionStorage.php
index 42f4a47fe6..0af23a493c 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\SectionStorage\SectionStorageManagerInterface::findByContext()
+   */
+  public $context_definitions = [];
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
index 0118768f77..13e3118797 100644
--- a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
+++ b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
@@ -5,6 +5,8 @@
 use Drupal\Core\Entity\Entity\EntityViewDisplay as BaseEntityViewDisplay;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
+use Drupal\Core\Plugin\Context\Context;
+use Drupal\Core\Plugin\Context\ContextDefinition;
 use Drupal\Core\Plugin\Context\EntityContext;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\field\Entity\FieldConfig;
@@ -274,11 +276,14 @@ 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();
-    }
-
-    return $this->getSections();
+    /** @var \Drupal\layout_builder\SectionStorageInterface $storage */
+    $storage = \Drupal::service('plugin.manager.layout_builder.section_storage')
+      ->findByContext('view', [
+        'view_mode' => new Context(ContextDefinition::create('string'), $this->getMode()),
+        'entity' => EntityContext::fromEntity($entity),
+        'display' => EntityContext::fromEntity($this),
+      ]);
+    return $storage ? $storage->getSections() : [];
   }
 
   /**
diff --git a/core/modules/layout_builder/src/Plugin/SectionStorage/DefaultsSectionStorage.php b/core/modules/layout_builder/src/Plugin/SectionStorage/DefaultsSectionStorage.php
index d35041d03d..f5f3cced8c 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,10 @@
  *
  * @SectionStorage(
  *   id = "defaults",
+ *   weight = 10,
+ *   context_definitions = {
+ *     "display" = @ContextDefinition("entity:entity_view_display"),
+ *   },
  * )
  *
  * @internal
@@ -90,12 +92,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('display');
   }
 
   /**
@@ -237,34 +235,49 @@ 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['display'] = EntityContext::fromEntity($entity);
     }
+    return $contexts;
+  }
 
+  /**
+   * Extracts an entity from the route values.
+   *
+   * @param mixed $value
+   *   The raw value from the route.
+   * @param array $defaults
+   *   The route defaults array.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface|null
+   *   The entity for the route, or NULL if none exist.
+   */
+  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..e9612e2d44 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_definitions = {
+ *     "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,42 @@ 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;
+  }
+
+  /**
+   * Extracts an entity from the route values.
+   *
+   * @param mixed $value
+   *   The raw value from the route.
+   * @param array $defaults
+   *   The route defaults array.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface|null
+   *   The entity for the route, or NULL if none exist.
+   */
+  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()));
   }
 
   /**
@@ -276,6 +286,12 @@ public function save() {
   public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
     $default_section_storage = $this->getDefaultSectionStorage();
     $result = AccessResult::allowedIf($default_section_storage->isLayoutBuilderEnabled())->addCacheableDependency($default_section_storage);
+
+    // Ensure there are sections available during view.
+    if ($operation === 'view') {
+      $overrides_available = ($default_section_storage->isOverridable() && count($this));
+      $result = $result->andIf(AccessResult::allowedIf($overrides_available))->addCacheableDependency($this->getEntity());
+    }
     return $return_as_object ? $result : $result->isAllowed();
   }
 
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/Routing/LayoutBuilderRoutesTrait.php b/core/modules/layout_builder/src/Routing/LayoutBuilderRoutesTrait.php
index d06b95324b..0fb62755d5 100644
--- a/core/modules/layout_builder/src/Routing/LayoutBuilderRoutesTrait.php
+++ b/core/modules/layout_builder/src/Routing/LayoutBuilderRoutesTrait.php
@@ -44,7 +44,7 @@ protected function buildLayoutRoutes(RouteCollection $collection, SectionStorage
     $defaults['section_storage'] = '';
     // Trigger the layout builder access check.
     $requirements['_has_layout_section'] = 'true';
-    $requirements['_layout_builder_access'] = 'view';
+    $requirements['_layout_builder_access'] = 'update';
     // Trigger the layout builder RouteEnhancer.
     $options['_layout_builder'] = TRUE;
     // Trigger the layout builder param converter.
diff --git a/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php b/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php
index 263b767f72..e5976ca0bd 100644
--- a/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php
+++ b/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php
@@ -45,11 +45,17 @@ public function __construct(LayoutTempstoreRepositoryInterface $layout_tempstore
    * {@inheritdoc}
    */
   public function convert($value, $definition, $name, array $defaults) {
-    if (isset($defaults['section_storage_type']) && $this->sectionStorageManager->hasDefinition($defaults['section_storage_type'])) {
-      if ($section_storage = $this->sectionStorageManager->loadFromRoute($defaults['section_storage_type'], $value, $definition, $name, $defaults)) {
-        // Pass the plugin through the tempstore repository.
-        return $this->layoutTempstoreRepository->get($section_storage);
-      }
+    // If no section storage type is specified or if it is invalid, return.
+    if (!isset($defaults['section_storage_type']) || !$this->sectionStorageManager->hasDefinition($defaults['section_storage_type'])) {
+      return NULL;
+    }
+
+    // Load an empty instance and derive the available contexts.
+    $contexts = $this->sectionStorageManager->loadEmpty($defaults['section_storage_type'])->getContextsFromRoute($value, $definition, $name, $defaults);
+    // Attempt to load a full instance based on the context.
+    if ($section_storage = $this->sectionStorageManager->load($defaults['section_storage_type'], $contexts)) {
+      // Pass the plugin through the tempstore repository.
+      return $this->layoutTempstoreRepository->get($section_storage);
     }
   }
 
diff --git a/core/modules/layout_builder/src/SectionStorage/SectionStorageDefinition.php b/core/modules/layout_builder/src/SectionStorage/SectionStorageDefinition.php
index 61b975a471..bccd7d1484 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_definitions'])) {
+      foreach ($definition['context_definitions'] as $name => $context_definition) {
+        $this->addContextDefinition($name, $context_definition);
+      }
+      unset($definition['context_definitions']);
+    }
+
     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..c65a79ba72 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\ContextHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\layout_builder\Annotation\SectionStorage;
 use Drupal\layout_builder\SectionStorageInterface;
@@ -11,6 +13,12 @@
 /**
  * Provides the Section Storage type plugin manager.
  *
+ * Note that while this class extends \Drupal\Core\Plugin\DefaultPluginManager
+ * and includes many additional public methods, only some of them are available
+ * via \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface.
+ * While internally depending on the parent class is necessary, external code
+ * should only use the methods available on that interface.
+ *
  * @internal
  *   Layout Builder is currently experimental and should only be leveraged by
  *   experimental modules and development releases of contributed modules.
@@ -18,6 +26,13 @@
  */
 class SectionStorageManager extends DefaultPluginManager implements SectionStorageManagerInterface {
 
+  /**
+   * The context handler.
+   *
+   * @var \Drupal\Core\Plugin\Context\ContextHandlerInterface
+   */
+  protected $contextHandler;
+
   /**
    * Constructs a new SectionStorageManager object.
    *
@@ -28,10 +43,14 @@ class SectionStorageManager extends DefaultPluginManager implements SectionStora
    *   Cache backend instance to use.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to invoke the alter hook with.
+   * @param \Drupal\Core\Plugin\Context\ContextHandlerInterface $context_handler
+   *   The context handler.
    */
-  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler, ContextHandlerInterface $context_handler) {
     parent::__construct('Plugin/SectionStorage', $namespaces, $module_handler, SectionStorageInterface::class, SectionStorage::class);
 
+    $this->contextHandler = $context_handler;
+
     $this->alterInfo('layout_builder_section_storage');
     $this->setCacheBackend($cache_backend, 'layout_builder_section_storage_plugins');
   }
@@ -39,33 +58,53 @@ public function __construct(\Traversable $namespaces, CacheBackendInterface $cac
   /**
    * {@inheritdoc}
    */
-  public function loadEmpty($id) {
-    return $this->createInstance($id);
+  protected function findDefinitions() {
+    $definitions = parent::findDefinitions();
+
+    // Sort the definitions by their weight while preserving the original order
+    // for those with matching weights.
+    $weights = array_map(function (SectionStorageDefinition $definition) {
+      return $definition->getWeight();
+    }, $definitions);
+    $ids = array_keys($definitions);
+    array_multisort($weights, $ids, $definitions);
+    return $definitions;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function loadFromStorageId($type, $id) {
-    /** @var \Drupal\layout_builder\SectionStorageInterface $plugin */
-    $plugin = $this->createInstance($type);
-    return $plugin->setSectionList($plugin->getSectionListFromId($id));
+  public function load($type, array $contexts = []) {
+    $plugin = $this->loadEmpty($type);
+    try {
+      $this->contextHandler->applyContextMapping($plugin, $contexts);
+    }
+    catch (ContextException $e) {
+      return NULL;
+    }
+    return $plugin;
   }
 
   /**
    * {@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.
+  public function findByContext($operation, array $contexts) {
+    $storage_types = array_keys($this->contextHandler->filterPluginDefinitionsByContexts($contexts, $this->getDefinitions()));
+
+    foreach ($storage_types as $type) {
+      $plugin = $this->load($type, $contexts);
+      if ($plugin && $plugin->access($operation)) {
+        return $plugin;
       }
     }
+    return NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function loadEmpty($type) {
+    return $this->createInstance($type);
   }
 
 }
diff --git a/core/modules/layout_builder/src/SectionStorage/SectionStorageManagerInterface.php b/core/modules/layout_builder/src/SectionStorage/SectionStorageManagerInterface.php
index 3b269fcbba..ca87d7568c 100644
--- a/core/modules/layout_builder/src/SectionStorage/SectionStorageManagerInterface.php
+++ b/core/modules/layout_builder/src/SectionStorage/SectionStorageManagerInterface.php
@@ -15,51 +15,46 @@
 interface SectionStorageManagerInterface extends DiscoveryInterface {
 
   /**
-   * Loads a section storage with no associated section list.
+   * Loads a section storage with the provided contexts applied.
    *
-   * @param string $id
-   *   The ID of the section storage being instantiated.
+   * @param string $type
+   *   The section storage type.
+   * @param \Drupal\Component\Plugin\Context\ContextInterface[] $contexts
+   *   (optional) The contexts available for this storage to use.
    *
-   * @return \Drupal\layout_builder\SectionStorageInterface
-   *   The section storage.
+   * @return \Drupal\layout_builder\SectionStorageInterface|null
+   *   The section storage or NULL if its context requirements are not met.
    */
-  public function loadEmpty($id);
+  public function load($type, array $contexts = []);
 
   /**
-   * Loads a section storage populated with an existing section list.
+   * Finds the section storage to load based on available contexts.
    *
-   * @param string $type
-   *   The section storage type.
-   * @param string $id
-   *   The section list ID.
+   * @param string $operation
+   *   The access operation. See \Drupal\Core\Access\AccessibleInterface.
+   * @param \Drupal\Component\Plugin\Context\ContextInterface[] $contexts
+   *   The contexts which should be used to determine which storage to return.
    *
-   * @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 findByContext($operation, array $contexts);
 
   /**
-   * Loads a section storage populated with a section list derived from a route.
+   * Loads an empty section storage with no associated section list.
    *
    * @param string $type
-   *   The section storage type.
-   * @param string $value
-   *   The raw value.
-   * @param mixed $definition
-   *   The parameter definition provided in the route options.
-   * @param string $name
-   *   The name of the parameter.
-   * @param array $defaults
-   *   The route defaults array.
+   *   The type of section storage being instantiated.
    *
-   * @return \Drupal\layout_builder\SectionStorageInterface|null
-   *   The section storage if it could be loaded, or NULL otherwise.
+   * @return \Drupal\layout_builder\SectionStorageInterface
+   *   The section storage.
    *
-   * @see \Drupal\Core\ParamConverter\ParamConverterInterface::convert()
+   * @internal
+   *   Section storage relies on context to load section lists. Use ::load()
+   *   when that context is available. This method is intended for use by
+   *   collaborators of the plugins in build-time situations when section
+   *   storage type must be consulted.
    */
-  public function loadFromRoute($type, $value, $definition, $name, array $defaults);
+  public function loadEmpty($type);
 
 }
diff --git a/core/modules/layout_builder/src/SectionStorageInterface.php b/core/modules/layout_builder/src/SectionStorageInterface.php
index 90ce9072fd..8bf3e4a011 100644
--- a/core/modules/layout_builder/src/SectionStorageInterface.php
+++ b/core/modules/layout_builder/src/SectionStorageInterface.php
@@ -4,6 +4,7 @@
 
 use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\Core\Access\AccessibleInterface;
+use Drupal\Core\Plugin\ContextAwarePluginInterface;
 use Symfony\Component\Routing\RouteCollection;
 
 /**
@@ -14,7 +15,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, PluginInspectionInterface, ContextAwarePluginInterface, AccessibleInterface {
 
   /**
    * Returns an identifier for this storage.
@@ -34,36 +35,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.
    *
@@ -79,27 +50,7 @@ public function getSectionListFromId($id);
   public function buildRoutes(RouteCollection $collection);
 
   /**
-   * Gets the URL used when redirecting away from the Layout Builder UI.
-   *
-   * @return \Drupal\Core\Url
-   *   The URL object.
-   */
-  public function getRedirectUrl();
-
-  /**
-   * Gets the URL used to display the Layout Builder UI.
-   *
-   * @param string $rel
-   *   (optional) The link relationship type, for example: 'view' or 'disable'.
-   *   Defaults to 'view'.
-   *
-   * @return \Drupal\Core\Url
-   *   The URL object.
-   */
-  public function getLayoutBuilderUrl($rel = 'view');
-
-  /**
-   * Configures the plugin based on route values.
+   * Derives the available plugin contexts from route values.
    *
    * @param mixed $value
    *   The raw value.
@@ -110,21 +61,30 @@ 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 available plugin contexts.
    */
-  public function getContexts();
+  public function getContextsFromRoute($value, $definition, $name, array $defaults);
+
+  /**
+   * Gets the URL used when redirecting away from the Layout Builder UI.
+   *
+   * @return \Drupal\Core\Url
+   *   The URL object.
+   */
+  public function getRedirectUrl();
+
+  /**
+   * Gets the URL used to display the Layout Builder UI.
+   *
+   * @param string $rel
+   *   (optional) The link relationship type, for example: 'view' or 'disable'.
+   *   Defaults to 'view'.
+   *
+   * @return \Drupal\Core\Url
+   *   The URL object.
+   */
+  public function getLayoutBuilderUrl($rel = 'view');
 
   /**
    * Gets the label for the object using the sections.
diff --git a/core/modules/layout_builder/tests/modules/layout_builder_overrides_test/layout_builder_overrides_test.info.yml b/core/modules/layout_builder/tests/modules/layout_builder_overrides_test/layout_builder_overrides_test.info.yml
new file mode 100644
index 0000000000..f9ed711707
--- /dev/null
+++ b/core/modules/layout_builder/tests/modules/layout_builder_overrides_test/layout_builder_overrides_test.info.yml
@@ -0,0 +1,6 @@
+name: 'Layout Builder overrides test'
+type: module
+description: 'Support module for testing overriding layout building.'
+package: Testing
+version: VERSION
+core: 8.x
diff --git a/core/modules/layout_builder/tests/modules/layout_builder_overrides_test/layout_builder_overrides_test.module b/core/modules/layout_builder/tests/modules/layout_builder_overrides_test/layout_builder_overrides_test.module
new file mode 100644
index 0000000000..a66162095b
--- /dev/null
+++ b/core/modules/layout_builder/tests/modules/layout_builder_overrides_test/layout_builder_overrides_test.module
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * @file
+ * Provides hook implementations for Layout Builder overrides tests.
+ */
+
+use Drupal\layout_builder_overrides_test\Plugin\SectionStorage\TestOverridesSectionStorage;
+
+/**
+ * Implements hook_layout_builder_section_storage_alter().
+ */
+function layout_builder_overrides_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_overrides_test/src/Plugin/SectionStorage/TestOverridesSectionStorage.php b/core/modules/layout_builder/tests/modules/layout_builder_overrides_test/src/Plugin/SectionStorage/TestOverridesSectionStorage.php
new file mode 100644
index 0000000000..be128d9e23
--- /dev/null
+++ b/core/modules/layout_builder/tests/modules/layout_builder_overrides_test/src/Plugin/SectionStorage/TestOverridesSectionStorage.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Drupal\layout_builder_overrides_test\Plugin\SectionStorage;
+
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Session\AccountInterface;
+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();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
+    $result = AccessResult::allowed();
+    return $return_as_object ? $result : $result->isAllowed();
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/modules/layout_builder_test/config/schema/layout_builder_test.schema.yml b/core/modules/layout_builder/tests/modules/layout_builder_test/config/schema/layout_builder_test.schema.yml
new file mode 100644
index 0000000000..75050837fa
--- /dev/null
+++ b/core/modules/layout_builder/tests/modules/layout_builder_test/config/schema/layout_builder_test.schema.yml
@@ -0,0 +1,7 @@
+layout_builder_test.test_simple_config.*:
+  type: config_object
+  mapping:
+    sections:
+      type: sequence
+      sequence:
+        type: layout_builder.section
diff --git a/core/modules/layout_builder/tests/modules/layout_builder_test/src/Plugin/SectionStorage/SimpleConfigSectionStorage.php b/core/modules/layout_builder/tests/modules/layout_builder_test/src/Plugin/SectionStorage/SimpleConfigSectionStorage.php
new file mode 100644
index 0000000000..52f3fecf08
--- /dev/null
+++ b/core/modules/layout_builder/tests/modules/layout_builder_test/src/Plugin/SectionStorage/SimpleConfigSectionStorage.php
@@ -0,0 +1,211 @@
+<?php
+
+namespace Drupal\layout_builder_test\Plugin\SectionStorage;
+
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Plugin\Context\Context;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\Plugin\ContextAwarePluginBase;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Url;
+use Drupal\layout_builder\Plugin\SectionStorage\SectionStorageLocalTaskProviderInterface;
+use Drupal\layout_builder\Routing\LayoutBuilderRoutesTrait;
+use Drupal\layout_builder\Section;
+use Drupal\layout_builder\SectionStorage\SectionStorageTrait;
+use Drupal\layout_builder\SectionStorageInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * Provides section storage utilizing simple config.
+ *
+ * @SectionStorage(
+ *   id = "test_simple_config",
+ *   context_definitions = {
+ *     "config_id" = @ContextDefinition("string"),
+ *   }
+ * )
+ */
+class SimpleConfigSectionStorage extends ContextAwarePluginBase implements SectionStorageInterface, SectionStorageLocalTaskProviderInterface, ContainerFactoryPluginInterface {
+
+  use LayoutBuilderRoutesTrait;
+  use SectionStorageTrait;
+
+  /**
+   * The config factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * An array of sections.
+   *
+   * @var \Drupal\layout_builder\Section[]|null
+   */
+  protected $sections;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config_factory) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->configFactory = $config_factory;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('config.factory')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getStorageType() {
+    return $this->getPluginId();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getStorageId() {
+    return $this->getContextValue('config_id');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function label() {
+    return $this->getStorageId();
+  }
+
+  /**
+   * Returns the name to be used to store in the config system.
+   */
+  protected function getConfigName() {
+    return 'layout_builder_test.' . $this->getStorageType() . '.' . $this->getStorageId();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSections() {
+    if (is_null($this->sections)) {
+      $sections = $this->configFactory->get($this->getConfigName())->get('sections') ?: [];
+      $this->setSections(array_map([Section::class, 'fromArray'], $sections));
+    }
+    return $this->sections;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setSections(array $sections) {
+    $this->sections = array_values($sections);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save() {
+    $sections = array_map(function (Section $section) {
+      return $section->toArray();
+    }, $this->getSections());
+
+    $config = $this->configFactory->getEditable($this->getConfigName());
+    $return = $config->get('sections') ? SAVED_UPDATED : SAVED_NEW;
+    $config->set('sections', $sections)->save();
+    return $return;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildRoutes(RouteCollection $collection) {
+    $this->buildLayoutRoutes($collection, $this->getPluginDefinition(), 'layout-builder-test-simple-config/{id}');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getContextsFromRoute($value, $definition, $name, array $defaults) {
+    $contexts['config_id'] = new Context(new ContextDefinition('string'), $value ?: $defaults['id']);
+    return $contexts;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildLocalTasks($base_plugin_definition) {
+    $type = $this->getStorageType();
+    $local_tasks = [];
+    $local_tasks["layout_builder.$type.view"] = $base_plugin_definition + [
+      'route_name' => "layout_builder.$type.view",
+      'title' => $this->t('Layout'),
+      'base_route' => "layout_builder.$type.view",
+    ];
+    $local_tasks["layout_builder.$type.save"] = $base_plugin_definition + [
+      'route_name' => "layout_builder.$type.save",
+      'title' => $this->t('Save Layout'),
+      'parent_id' => "layout_builder_ui:layout_builder.$type.view",
+    ];
+    $local_tasks["layout_builder.$type.cancel"] = $base_plugin_definition + [
+      'route_name' => "layout_builder.$type.cancel",
+      'title' => $this->t('Cancel Layout'),
+      'parent_id' => "layout_builder_ui:layout_builder.$type.view",
+      'weight' => 5,
+    ];
+    return $local_tasks;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLayoutBuilderUrl($rel = 'view') {
+    return Url::fromRoute("layout_builder.{$this->getStorageType()}.$rel", ['id' => $this->getStorageId()]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRedirectUrl() {
+    return $this->getLayoutBuilderUrl();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
+    $result = AccessResult::allowed();
+    return $return_as_object ? $result : $result->isAllowed();
+  }
+
+  /**
+   * {@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/tests/src/Functional/LayoutBuilderSectionStorageTest.php b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderSectionStorageTest.php
new file mode 100644
index 0000000000..9f8a169a48
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderSectionStorageTest.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\Functional;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests the UI aspects of section storage.
+ *
+ * @group layout_builder
+ */
+class LayoutBuilderSectionStorageTest extends BrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'layout_builder',
+    'node',
+    'layout_builder_test',
+    'layout_builder_overrides_test',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // @todo The Layout Builder UI relies on local tasks; fix in
+    //   https://www.drupal.org/project/drupal/issues/2917777.
+    $this->drupalPlaceBlock('local_tasks_block');
+
+    // Create two nodes.
+    $this->createContentType(['type' => 'bundle_with_section_field']);
+    $this->createNode([
+      'type' => 'bundle_with_section_field',
+      'title' => 'The first node title',
+      'body' => [
+        [
+          'value' => 'The first node body',
+        ],
+      ],
+    ]);
+  }
+
+  /**
+   * Tests that section loading is delegated to plugins during rendering.
+   */
+  public function testRenderByContextAwarePluginDelegate() {
+    $this->drupalLogin($this->drupalCreateUser([
+      'configure any layout',
+      'administer node display',
+    ]));
+
+    $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));
+
+    $this->drupalGet('admin/structure/types/manage/bundle_with_section_field/display/default');
+    $this->drupalPostForm(NULL, ['layout[enabled]' => TRUE], 'Save');
+    $this->drupalPostForm(NULL, ['layout[allow_custom]' => TRUE], 'Save');
+
+    $this->drupalGet('node/1');
+    // 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('default', $view_mode);
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php
index 2d22829752..192ea6cfa9 100644
--- a/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php
+++ b/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\layout_builder\Functional;
 
+use Drupal\layout_builder\Section;
 use Drupal\node\Entity\Node;
 use Drupal\Tests\BrowserTestBase;
 use Drupal\views\Entity\View;
@@ -557,4 +558,30 @@ public function testBlockPlaceholder() {
     $assert_session->pageTextContains($block_content);
   }
 
+  /**
+   * Tests a config-based implementation of Layout Builder.
+   *
+   * @see \Drupal\layout_builder_test\Plugin\SectionStorage\SimpleConfigSectionStorage
+   */
+  public function testSimpleConfigBasedLayout() {
+    $assert_session = $this->assertSession();
+
+    $this->drupalLogin($this->createUser(['configure any layout']));
+
+    // Prepare an object with a pre-existing section.
+    $this->container->get('config.factory')->getEditable('layout_builder_test.test_simple_config.existing')
+      ->set('sections', [(new Section('layout_twocol'))->toArray()])
+      ->save();
+
+    // The pre-existing section is found.
+    $this->drupalGet('layout-builder-test-simple-config/existing');
+    $assert_session->elementsCount('css', '.layout', 1);
+    $assert_session->elementsCount('css', '.layout--twocol', 1);
+
+    // The default layout is selected for a new object.
+    $this->drupalGet('layout-builder-test-simple-config/new');
+    $assert_session->elementsCount('css', '.layout', 1);
+    $assert_session->elementsCount('css', '.layout--onecol', 1);
+  }
+
 }
diff --git a/core/modules/layout_builder/tests/src/Kernel/OverridesSectionStorageTest.php b/core/modules/layout_builder/tests/src/Kernel/OverridesSectionStorageTest.php
new file mode 100644
index 0000000000..a2c5f6a809
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Kernel/OverridesSectionStorageTest.php
@@ -0,0 +1,92 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\Kernel;
+
+use Drupal\Core\Plugin\Context\EntityContext;
+use Drupal\entity_test\Entity\EntityTest;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
+use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage;
+use Drupal\layout_builder\Section;
+use Drupal\layout_builder\SectionComponent;
+use Drupal\layout_builder\SectionStorage\SectionStorageDefinition;
+
+/**
+ * @coversDefaultClass \Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage
+ *
+ * @group layout_builder
+ */
+class OverridesSectionStorageTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'layout_discovery',
+    'layout_builder',
+    'entity_test',
+    'field',
+    'system',
+    'user',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installSchema('system', ['key_value_expire']);
+    $this->installEntitySchema('entity_test');
+  }
+
+  /**
+   * @covers ::access
+   * @dataProvider providerTestAccess
+   */
+  public function testAccess($expected, $operation, $is_enabled, $section_data) {
+    $display = LayoutBuilderEntityViewDisplay::create([
+      'targetEntityType' => 'entity_test',
+      'bundle' => 'entity_test',
+      'mode' => 'default',
+      'status' => TRUE,
+    ]);
+    if ($is_enabled) {
+      $display->enableLayoutBuilder();
+    }
+    $display
+      ->setOverridable()
+      ->save();
+
+    $entity = EntityTest::create(['layout_builder__layout' => $section_data]);
+    $entity->save();
+
+    $plugin = OverridesSectionStorage::create($this->container, [], 'overrides', new SectionStorageDefinition());
+    $plugin->setContext('entity', EntityContext::fromEntity($entity));
+    $result = $plugin->access($operation);
+    $this->assertSame($expected, $result);
+  }
+
+  /**
+   * Provides test data for ::testAccess().
+   */
+  public function providerTestAccess() {
+    $section_data = [
+      new Section('layout_default', [], [
+        'first-uuid' => new SectionComponent('first-uuid', 'content', ['id' => 'foo']),
+      ]),
+    ];
+
+    $data = [];
+    $data['view, disabled, no data'] = [FALSE, 'view', FALSE, []];
+    $data['view, enabled, no data'] = [FALSE, 'view', TRUE, []];
+    $data['view, disabled, data'] = [FALSE, 'view', FALSE, $section_data];
+    $data['view, enabled, data'] = [TRUE, 'view', TRUE, $section_data];
+    $data['update, disabled, no data'] = [FALSE, 'update', FALSE, []];
+    $data['update, enabled, no data'] = [TRUE, 'update', TRUE, []];
+    $data['update, disabled, data'] = [FALSE, 'update', FALSE, $section_data];
+    $data['update, enabled, data'] = [TRUE, 'update', TRUE, $section_data];
+    return $data;
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Kernel/SimpleConfigSectionStorageTest.php b/core/modules/layout_builder/tests/src/Kernel/SimpleConfigSectionStorageTest.php
new file mode 100644
index 0000000000..282bb2022c
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Kernel/SimpleConfigSectionStorageTest.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\Kernel;
+
+use Drupal\Core\Plugin\Context\Context;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\layout_builder\Section;
+use Drupal\layout_builder\SectionStorage\SectionStorageDefinition;
+use Drupal\layout_builder_test\Plugin\SectionStorage\SimpleConfigSectionStorage;
+
+/**
+ * Tests the test implementation of section storage.
+ *
+ * @coversDefaultClass \Drupal\layout_builder_test\Plugin\SectionStorage\SimpleConfigSectionStorage
+ *
+ * @group layout_builder
+ */
+class SimpleConfigSectionStorageTest extends SectionStorageTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'layout_builder_test',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getSectionStorage(array $section_data) {
+    $config = $this->container->get('config.factory')->getEditable('layout_builder_test.test_simple_config.foobar');
+    $section_data = array_map(function (Section $section) {
+      return $section->toArray();
+    }, $section_data);
+    $config->set('sections', $section_data)->save();
+
+    $definition = new SectionStorageDefinition(['id' => 'test_simple_config']);
+    $plugin = SimpleConfigSectionStorage::create($this->container, [], 'test_simple_config', $definition);
+    $plugin->setContext('config_id', new Context(new ContextDefinition('string'), 'foobar'));
+    return $plugin;
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php b/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php
index d30917a446..49e3ee0ff4 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('display', $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);
   }
 
@@ -254,7 +236,7 @@ public function testBuildRoutes() {
         [
           '_field_ui_view_mode_access' => 'administer with_bundle_key display',
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
         ],
         [
           'parameters' => [
@@ -276,7 +258,7 @@ public function testBuildRoutes() {
         [
           '_field_ui_view_mode_access' => 'administer with_bundle_key display',
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
         ],
         [
           'parameters' => [
@@ -298,7 +280,7 @@ public function testBuildRoutes() {
         [
           '_field_ui_view_mode_access' => 'administer with_bundle_key display',
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
         ],
         [
           'parameters' => [
@@ -320,7 +302,7 @@ public function testBuildRoutes() {
         [
           '_field_ui_view_mode_access' => 'administer with_bundle_key display',
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
         ],
         [
           'parameters' => [
@@ -341,7 +323,7 @@ public function testBuildRoutes() {
         [
           '_field_ui_view_mode_access' => 'administer with_bundle_parameter display',
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
         ],
         [
           'parameters' => [
@@ -362,7 +344,7 @@ public function testBuildRoutes() {
         [
           '_field_ui_view_mode_access' => 'administer with_bundle_parameter display',
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
         ],
         [
           'parameters' => [
@@ -383,7 +365,7 @@ public function testBuildRoutes() {
         [
           '_field_ui_view_mode_access' => 'administer with_bundle_parameter display',
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
         ],
         [
           'parameters' => [
@@ -404,7 +386,7 @@ public function testBuildRoutes() {
         [
           '_field_ui_view_mode_access' => 'administer with_bundle_parameter display',
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
         ],
         [
           'parameters' => [
diff --git a/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreParamConverterTest.php b/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreParamConverterTest.php
index 5f8dc051e3..1091cd586f 100644
--- a/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreParamConverterTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreParamConverterTest.php
@@ -32,9 +32,11 @@ public function testConvert() {
     $expected = 'the_return_value';
 
     $section_storage_manager->hasDefinition('my_type')->willReturn(TRUE);
-    $section_storage_manager->loadFromRoute('my_type', $value, $definition, $name, $defaults)->willReturn($section_storage);
+    $section_storage_manager->loadEmpty('my_type')->willReturn($section_storage->reveal());
+    $section_storage->getContextsFromRoute($value, $definition, $name, $defaults)->willReturn([]);
+    $section_storage_manager->load('my_type', [])->willReturn($section_storage->reveal());
 
-    $layout_tempstore_repository->get($section_storage->reveal())->willReturn($expected);
+    $layout_tempstore_repository->get($section_storage)->willReturn($expected);
 
     $result = $converter->convert($value, $definition, $name, $defaults);
     $this->assertEquals($expected, $result);
@@ -54,7 +56,7 @@ public function testConvertNoType() {
     $defaults = ['section_storage_type' => NULL];
 
     $section_storage_manager->hasDefinition()->shouldNotBeCalled();
-    $section_storage_manager->loadFromRoute()->shouldNotBeCalled();
+    $section_storage_manager->load()->shouldNotBeCalled();
     $layout_tempstore_repository->get()->shouldNotBeCalled();
 
     $result = $converter->convert($value, $definition, $name, $defaults);
@@ -75,7 +77,7 @@ public function testConvertInvalidConverter() {
     $defaults = ['section_storage_type' => 'invalid'];
 
     $section_storage_manager->hasDefinition('invalid')->willReturn(FALSE);
-    $section_storage_manager->loadFromRoute()->shouldNotBeCalled();
+    $section_storage_manager->load()->shouldNotBeCalled();
     $layout_tempstore_repository->get()->shouldNotBeCalled();
 
     $result = $converter->convert($value, $definition, $name, $defaults);
diff --git a/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php b/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
index 110ec2021e..029bcacf94 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,
@@ -223,7 +187,7 @@ public function testBuildRoutes() {
         ],
         [
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
         ],
         [
           'parameters' => [
@@ -243,7 +207,7 @@ public function testBuildRoutes() {
         ],
         [
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
         ],
         [
           'parameters' => [
@@ -263,7 +227,7 @@ public function testBuildRoutes() {
         ],
         [
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
         ],
         [
           'parameters' => [
@@ -283,7 +247,7 @@ public function testBuildRoutes() {
         ],
         [
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
         ],
         [
           'parameters' => [
@@ -305,7 +269,7 @@ public function testBuildRoutes() {
         ],
         [
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
           'with_integer_id' => '\d+',
         ],
         [
@@ -326,7 +290,7 @@ public function testBuildRoutes() {
         ],
         [
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
           'with_integer_id' => '\d+',
         ],
         [
@@ -347,7 +311,7 @@ public function testBuildRoutes() {
         ],
         [
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
           'with_integer_id' => '\d+',
         ],
         [
@@ -368,7 +332,7 @@ public function testBuildRoutes() {
         ],
         [
           '_has_layout_section' => 'true',
-          '_layout_builder_access' => 'view',
+          '_layout_builder_access' => 'update',
           'with_integer_id' => '\d+',
         ],
         [
diff --git a/core/modules/layout_builder/tests/src/Unit/SectionStorageManagerTest.php b/core/modules/layout_builder/tests/src/Unit/SectionStorageManagerTest.php
index 392cd8939e..3a33ede44f 100644
--- a/core/modules/layout_builder/tests/src/Unit/SectionStorageManagerTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/SectionStorageManagerTest.php
@@ -2,10 +2,16 @@
 
 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\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 +26,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 +57,147 @@ 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->plugin = $this->prophesize(SectionStorageInterface::class);
-
-    $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());
+    $this->contextHandler = $this->prophesize(ContextHandlerInterface::class);
+    $this->manager = new TestSectionStorageManager($this->discovery->reveal(), $this->factory->reveal(), $cache->reveal(), $module_handler->reveal(), $this->contextHandler->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);
+    $this->assertSame($plugin->reveal(), $result);
   }
 
   /**
-   * @covers ::loadFromStorageId
+   * @covers ::load
    */
-  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);
-  }
+  public function testLoad() {
+    $plugin = $this->prophesize(SectionStorageInterface::class);
+    $this->factory->createInstance('the_plugin_id', [])->willReturn($plugin->reveal());
 
-  /**
-   * @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;
-    });
-
-    $result = $this->manager->loadFromRoute('the_plugin_id', 'the_value', [], 'the_parameter_name', []);
-    $this->assertInstanceOf(SectionStorageInterface::class, $result);
+    $contexts = [
+      'the_context' => $this->prophesize(ContextInterface::class)->reveal(),
+    ];
+
+    $this->contextHandler->applyContextMapping($plugin, $contexts)->shouldBeCalled();
+
+    $result = $this->manager->load('the_plugin_id', $contexts);
+    $this->assertSame($plugin->reveal(), $result);
   }
 
   /**
-   * @covers ::loadFromRoute
+   * @covers ::load
    */
-  public function testLoadFromRouteNull() {
-    $this->plugin->extractIdFromRoute('the_value', [], 'the_parameter_name', ['_route' => 'the_route_name'])->willReturn(NULL);
+  public function testLoadNull() {
+    $plugin = $this->prophesize(SectionStorageInterface::class);
+    $this->factory->createInstance('the_plugin_id', [])->willReturn($plugin->reveal());
+
+    $contexts = [
+      'the_context' => $this->prophesize(ContextInterface::class)->reveal(),
+    ];
+
+    $this->contextHandler->applyContextMapping($plugin, $contexts)->willThrow(new ContextException());
 
-    $result = $this->manager->loadFromRoute('the_plugin_id', 'the_value', [], 'the_parameter_name', ['_route' => 'the_route_name']);
+    $result = $this->manager->load('the_plugin_id', $contexts);
     $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 ::findByContext
+   *
+   * @dataProvider providerTestFindByContext
+   */
+  public function testFindByContext($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('test_operation')->willReturn($access);
+
+    $no_access = $this->prophesize(SectionStorageInterface::class);
+    $no_access->access('test_operation')->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->findByContext('test_operation', $contexts);
+    if ($access) {
+      $this->assertSame($provider_access->reveal(), $result);
+    }
+    else {
+      $this->assertNull($result);
+    }
+  }
+
+  /**
+   * Provides test data for ::testFindByContext().
+   */
+  public function providerTestFindByContext() {
+    $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, ContextHandlerInterface $context_handler) {
+    parent::__construct(new \ArrayObject(), $cache_backend, $module_handler, $context_handler);
+    $this->discovery = $discovery;
+    $this->factory = $factory;
+  }
+
 }
