diff --git a/core/modules/layout_builder/layout_builder.module b/core/modules/layout_builder/layout_builder.module
index 80339c1f70e591efaa20d4e3aac5c9808f64b13c..b1ecb5d594d0025412591e9a9056202f406423af 100644
--- a/core/modules/layout_builder/layout_builder.module
+++ b/core/modules/layout_builder/layout_builder.module
@@ -73,9 +73,8 @@ function layout_builder_form_entity_form_display_edit_form_alter(&$form, FormSta
  */
 function layout_builder_field_config_insert(FieldConfigInterface $field_config) {
   // Clear the sample entity for this entity type and bundle.
-  /** @var \Drupal\Core\TempStore\SharedTempStore $tempstore */
-  $tempstore = \Drupal::service('tempstore.shared')->get('layout_builder.sample_entity');
-  $tempstore->delete($field_config->getTargetEntityTypeId() . '.' . $field_config->getTargetBundle());
+  $sample_entity_generator = \Drupal::service('layout_builder.sample_entity_generator');
+  $sample_entity_generator->delete($field_config->getTargetEntityTypeId(), $field_config->getTargetBundle());
   \Drupal::service('plugin.manager.block')->clearCachedDefinitions();
 }
 
@@ -84,8 +83,7 @@ function layout_builder_field_config_insert(FieldConfigInterface $field_config)
  */
 function layout_builder_field_config_delete(FieldConfigInterface $field_config) {
   // Clear the sample entity for this entity type and bundle.
-  /** @var \Drupal\Core\TempStore\SharedTempStore $tempstore */
-  $tempstore = \Drupal::service('tempstore.shared')->get('layout_builder.sample_entity');
-  $tempstore->delete($field_config->getTargetEntityTypeId() . '.' . $field_config->getTargetBundle());
+  $sample_entity_generator = \Drupal::service('layout_builder.sample_entity_generator');
+  $sample_entity_generator->delete($field_config->getTargetEntityTypeId(), $field_config->getTargetBundle());
   \Drupal::service('plugin.manager.block')->clearCachedDefinitions();
 }
diff --git a/core/modules/layout_builder/layout_builder.routing.yml b/core/modules/layout_builder/layout_builder.routing.yml
index 98465538625e108da9f8bf1f80c133b4984cabdb..322e2301c11b9a69f37ae588b581174f53c5bd47 100644
--- a/core/modules/layout_builder/layout_builder.routing.yml
+++ b/core/modules/layout_builder/layout_builder.routing.yml
@@ -115,6 +115,3 @@ layout_builder.move_block:
     parameters:
       section_storage:
         layout_builder_tempstore: TRUE
-
-route_callbacks:
-  - 'layout_builder.routes:getRoutes'
diff --git a/core/modules/layout_builder/layout_builder.services.yml b/core/modules/layout_builder/layout_builder.services.yml
index 38933073d965a097cb4b2d57ad33e5357d8cb86b..778a6d5fa60ce8ef3ec92e025bf5d1ae7d19e39c 100644
--- a/core/modules/layout_builder/layout_builder.services.yml
+++ b/core/modules/layout_builder/layout_builder.services.yml
@@ -6,9 +6,12 @@ services:
     class: Drupal\layout_builder\Access\LayoutSectionAccessCheck
     tags:
       - { name: access_check, applies_to: _has_layout_section }
+  plugin.manager.layout_builder.section_storage:
+    class: Drupal\layout_builder\SectionStorage\SectionStorageManager
+    parent: default_plugin_manager
   layout_builder.routes:
     class: Drupal\layout_builder\Routing\LayoutBuilderRoutes
-    arguments: ['@entity_type.manager', '@entity_field.manager']
+    arguments: ['@plugin.manager.layout_builder.section_storage']
     tags:
      - { name: event_subscriber }
   layout_builder.route_enhancer:
@@ -17,17 +20,14 @@ services:
       - { name: route_enhancer }
   layout_builder.param_converter:
     class: Drupal\layout_builder\Routing\LayoutTempstoreParamConverter
-    arguments: ['@layout_builder.tempstore_repository', '@class_resolver']
+    arguments: ['@layout_builder.tempstore_repository', '@plugin.manager.layout_builder.section_storage']
     tags:
       - { name: paramconverter, priority: 10 }
-  layout_builder.section_storage_param_converter.defaults:
-    class: Drupal\layout_builder\Routing\SectionStorageDefaultsParamConverter
-    arguments: ['@entity.manager']
-  layout_builder.section_storage_param_converter.overrides:
-    class: Drupal\layout_builder\Routing\SectionStorageOverridesParamConverter
-    arguments: ['@entity.manager']
   cache_context.layout_builder_is_active:
     class: Drupal\layout_builder\Cache\LayoutBuilderIsActiveCacheContext
     arguments: ['@current_route_match']
     tags:
       - { name: cache.context}
+  layout_builder.sample_entity_generator:
+    class: Drupal\layout_builder\Entity\LayoutBuilderSampleEntityGenerator
+    arguments: ['@tempstore.shared', '@entity_type.manager']
diff --git a/core/modules/layout_builder/src/Annotation/SectionStorage.php b/core/modules/layout_builder/src/Annotation/SectionStorage.php
new file mode 100644
index 0000000000000000000000000000000000000000..42f4a47fe677acc888be293bd715e849ad28174d
--- /dev/null
+++ b/core/modules/layout_builder/src/Annotation/SectionStorage.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Drupal\layout_builder\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+use Drupal\layout_builder\SectionStorage\SectionStorageDefinition;
+
+/**
+ * Defines a Section Storage type annotation object.
+ *
+ * @see \Drupal\layout_builder\SectionStorage\SectionStorageManager
+ * @see plugin_api
+ *
+ * @Annotation
+ */
+class SectionStorage extends Plugin {
+
+  /**
+   * The plugin ID.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get() {
+    return new SectionStorageDefinition($this->definition);
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Controller/LayoutBuilderController.php b/core/modules/layout_builder/src/Controller/LayoutBuilderController.php
index 9642c4e2a70a3d17070dbe5048e78fd4dced384e..8f7666f579a570920a045d9bc610523688afe262 100644
--- a/core/modules/layout_builder/src/Controller/LayoutBuilderController.php
+++ b/core/modules/layout_builder/src/Controller/LayoutBuilderController.php
@@ -305,7 +305,7 @@ public function saveLayout(SectionStorageInterface $section_storage) {
       $this->messenger->addMessage($this->t('The layout has been saved.'));
     }
 
-    return new RedirectResponse($section_storage->getCanonicalUrl()->setAbsolute()->toString());
+    return new RedirectResponse($section_storage->getRedirectUrl()->setAbsolute()->toString());
   }
 
   /**
@@ -322,7 +322,7 @@ public function cancelLayout(SectionStorageInterface $section_storage) {
 
     $this->messenger->addMessage($this->t('The changes to the layout have been discarded.'));
 
-    return new RedirectResponse($section_storage->getCanonicalUrl()->setAbsolute()->toString());
+    return new RedirectResponse($section_storage->getRedirectUrl()->setAbsolute()->toString());
   }
 
 }
diff --git a/core/modules/layout_builder/src/DefaultsSectionStorageInterface.php b/core/modules/layout_builder/src/DefaultsSectionStorageInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..9397c6cea58506536528c28282e1335c63592097
--- /dev/null
+++ b/core/modules/layout_builder/src/DefaultsSectionStorageInterface.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Drupal\layout_builder;
+
+/**
+ * Defines an interface for an object that stores layout sections for defaults.
+ *
+ * @internal
+ *   Layout Builder is currently experimental and should only be leveraged by
+ *   experimental modules and development releases of contributed modules.
+ *   See https://www.drupal.org/core/experimental for more information.
+ */
+interface DefaultsSectionStorageInterface extends SectionStorageInterface {
+
+  /**
+   * Determines if the defaults allow custom overrides.
+   *
+   * @return bool
+   *   TRUE if custom overrides are allowed, FALSE otherwise.
+   */
+  public function isOverridable();
+
+  /**
+   * Sets the defaults to allow or disallow overrides.
+   *
+   * @param bool $overridable
+   *   TRUE if the display should allow overrides, FALSE otherwise.
+   *
+   * @return $this
+   */
+  public function setOverridable($overridable = TRUE);
+
+}
diff --git a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
index 9ed5f73ecb5e874994ff7dde3f31afaa39b472c0..2582d5c7ed0c9f3e5f18dbbe0a6c8982d74f520f 100644
--- a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
+++ b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
@@ -5,18 +5,17 @@
 use Drupal\Component\Plugin\DependentPluginInterface;
 use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\Component\Utility\NestedArray;
-use Drupal\Core\Entity\ContentEntityStorageInterface;
 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\StringTranslation\TranslatableMarkup;
-use Drupal\Core\Url;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\field\Entity\FieldStorageConfig;
 use Drupal\layout_builder\Section;
 use Drupal\layout_builder\SectionComponent;
+use Drupal\layout_builder\SectionStorage\SectionStorageTrait;
 
 /**
  * Provides an entity view display entity that has a layout.
@@ -28,6 +27,8 @@
  */
 class LayoutBuilderEntityViewDisplay extends BaseEntityViewDisplay implements LayoutEntityDisplayInterface {
 
+  use SectionStorageTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -51,104 +52,13 @@ public function getSections() {
   }
 
   /**
-   * Store the information for all sections.
-   *
-   * @param \Drupal\layout_builder\Section[] $sections
-   *   The sections information.
-   *
-   * @return $this
+   * {@inheritdoc}
    */
   protected function setSections(array $sections) {
     $this->setThirdPartySetting('layout_builder', 'sections', array_values($sections));
     return $this;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function count() {
-    return count($this->getSections());
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getSection($delta) {
-    if (!$this->hasSection($delta)) {
-      throw new \OutOfBoundsException(sprintf('Invalid delta "%s" for the "%s" entity', $delta, $this->id()));
-    }
-
-    return $this->getSections()[$delta];
-  }
-
-  /**
-   * Sets the section for the given delta on the display.
-   *
-   * @param int $delta
-   *   The delta of the section.
-   * @param \Drupal\layout_builder\Section $section
-   *   The layout section.
-   *
-   * @return $this
-   */
-  protected function setSection($delta, Section $section) {
-    $sections = $this->getSections();
-    $sections[$delta] = $section;
-    $this->setSections($sections);
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function appendSection(Section $section) {
-    $delta = $this->count();
-
-    $this->setSection($delta, $section);
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function insertSection($delta, Section $section) {
-    if ($this->hasSection($delta)) {
-      $sections = $this->getSections();
-      // @todo Use https://www.drupal.org/node/66183 once resolved.
-      $start = array_slice($sections, 0, $delta);
-      $end = array_slice($sections, $delta);
-      $this->setSections(array_merge($start, [$section], $end));
-    }
-    else {
-      $this->appendSection($section);
-    }
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function removeSection($delta) {
-    $sections = $this->getSections();
-    unset($sections[$delta]);
-    $this->setSections($sections);
-    return $this;
-  }
-
-  /**
-   * Indicates if there is a section at the specified delta.
-   *
-   * @param int $delta
-   *   The delta of the section.
-   *
-   * @return bool
-   *   TRUE if there is a section for this delta, FALSE otherwise.
-   */
-  protected function hasSection($delta) {
-    $sections = $this->getSections();
-    return isset($sections[$delta]);
-  }
-
   /**
    * {@inheritdoc}
    */
@@ -255,50 +165,6 @@ public function buildMultiple(array $entities) {
     return $build_list;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getContexts() {
-    $entity = $this->getSampleEntity($this->getTargetEntityTypeId(), $this->getTargetBundle());
-    $context_label = new TranslatableMarkup('@entity being viewed', ['@entity' => $entity->getEntityType()->getLabel()]);
-
-    // @todo Use EntityContextDefinition after resolving
-    //   https://www.drupal.org/node/2932462.
-    $contexts = [];
-    $contexts['layout_builder.entity'] = new Context(new ContextDefinition("entity:{$entity->getEntityTypeId()}", $context_label), $entity);
-    return $contexts;
-  }
-
-  /**
-   * Returns a sample entity.
-   *
-   * @param string $entity_type_id
-   *   The entity type ID.
-   * @param string $bundle_id
-   *   The bundle ID.
-   *
-   * @return \Drupal\Core\Entity\EntityInterface
-   *   An entity.
-   */
-  protected function getSampleEntity($entity_type_id, $bundle_id) {
-    /** @var \Drupal\Core\TempStore\SharedTempStore $tempstore */
-    $tempstore = \Drupal::service('tempstore.shared')->get('layout_builder.sample_entity');
-    if ($entity = $tempstore->get("$entity_type_id.$bundle_id")) {
-      return $entity;
-    }
-
-    $entity_storage = $this->entityTypeManager()->getStorage($entity_type_id);
-    if (!$entity_storage instanceof ContentEntityStorageInterface) {
-      throw new \InvalidArgumentException(sprintf('The "%s" entity storage is not supported', $entity_type_id));
-    }
-
-    $entity = $entity_storage->createWithSampleValues($bundle_id);
-    // Mark the sample entity as being a preview.
-    $entity->in_preview = TRUE;
-    $tempstore->set("$entity_type_id.$bundle_id", $entity);
-    return $entity;
-  }
-
   /**
    * Gets the runtime sections for a given entity.
    *
@@ -328,51 +194,6 @@ public function label() {
     return new TranslatableMarkup('@bundle @label', ['@bundle' => $bundle_label, '@label' => $target_entity_type->getPluralLabel()]);
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public static function getStorageType() {
-    return 'defaults';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getStorageId() {
-    return $this->id();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCanonicalUrl() {
-    return Url::fromRoute("entity.entity_view_display.{$this->getTargetEntityTypeId()}.view_mode", $this->getRouteParameters());
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getLayoutBuilderUrl() {
-    return Url::fromRoute("entity.entity_view_display.{$this->getTargetEntityTypeId()}.layout_builder", $this->getRouteParameters());
-  }
-
-  /**
-   * Returns the route parameters needed to build routes for this entity.
-   *
-   * @return string[]
-   *   An array of route parameters.
-   */
-  protected function getRouteParameters() {
-    $route_parameters = [];
-
-    $entity_type = $this->entityTypeManager()->getDefinition($this->getTargetEntityTypeId());
-    $bundle_parameter_key = $entity_type->getBundleEntityType() ?: 'bundle';
-    $route_parameters[$bundle_parameter_key] = $this->getTargetBundle();
-
-    $route_parameters['view_mode_name'] = $this->getMode();
-    return $route_parameters;
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/layout_builder/src/Entity/LayoutBuilderSampleEntityGenerator.php b/core/modules/layout_builder/src/Entity/LayoutBuilderSampleEntityGenerator.php
new file mode 100644
index 0000000000000000000000000000000000000000..9f606070e3fd8ea914811c0511e71deccf1f8450
--- /dev/null
+++ b/core/modules/layout_builder/src/Entity/LayoutBuilderSampleEntityGenerator.php
@@ -0,0 +1,91 @@
+<?php
+
+namespace Drupal\layout_builder\Entity;
+
+use Drupal\Core\Entity\ContentEntityStorageInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\TempStore\SharedTempStoreFactory;
+
+/**
+ * Generates a sample entity for use by the Layout Builder.
+ *
+ * @internal
+ *   Layout Builder is currently experimental and should only be leveraged by
+ *   experimental modules and development releases of contributed modules.
+ *   See https://www.drupal.org/core/experimental for more information.
+ */
+class LayoutBuilderSampleEntityGenerator {
+
+  /**
+   * The shared tempstore factory.
+   *
+   * @var \Drupal\Core\TempStore\SharedTempStoreFactory
+   */
+  protected $tempStoreFactory;
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * LayoutBuilderSampleEntityGenerator constructor.
+   *
+   * @param \Drupal\Core\TempStore\SharedTempStoreFactory $temp_store_factory
+   *   The tempstore factory.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   */
+  public function __construct(SharedTempStoreFactory $temp_store_factory, EntityTypeManagerInterface $entity_type_manager) {
+    $this->tempStoreFactory = $temp_store_factory;
+    $this->entityTypeManager = $entity_type_manager;
+  }
+
+  /**
+   * Gets a sample entity for a given entity type and bundle.
+   *
+   * @param string $entity_type_id
+   *   The entity type ID.
+   * @param string $bundle_id
+   *   The bundle ID.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface
+   *   An entity.
+   */
+  public function get($entity_type_id, $bundle_id) {
+    $tempstore = $this->tempStoreFactory->get('layout_builder.sample_entity');
+    if ($entity = $tempstore->get("$entity_type_id.$bundle_id")) {
+      return $entity;
+    }
+
+    $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
+    if (!$entity_storage instanceof ContentEntityStorageInterface) {
+      throw new \InvalidArgumentException(sprintf('The "%s" entity storage is not supported', $entity_type_id));
+    }
+
+    $entity = $entity_storage->createWithSampleValues($bundle_id);
+    // Mark the sample entity as being a preview.
+    $entity->in_preview = TRUE;
+    $tempstore->set("$entity_type_id.$bundle_id", $entity);
+    return $entity;
+  }
+
+  /**
+   * Deletes a sample entity for a given entity type and bundle.
+   *
+   * @param string $entity_type_id
+   *   The entity type ID.
+   * @param string $bundle_id
+   *   The bundle ID.
+   *
+   * @return $this
+   */
+  public function delete($entity_type_id, $bundle_id) {
+    $tempstore = $this->tempStoreFactory->get('layout_builder.sample_entity');
+    $tempstore->delete("$entity_type_id.$bundle_id");
+    return $this;
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Entity/LayoutEntityDisplayInterface.php b/core/modules/layout_builder/src/Entity/LayoutEntityDisplayInterface.php
index 1affc53b399418fe6edf519ff6fdde0a0b2a535d..b8fd21d822b224dcb266ff7f45b8644b03f4c50f 100644
--- a/core/modules/layout_builder/src/Entity/LayoutEntityDisplayInterface.php
+++ b/core/modules/layout_builder/src/Entity/LayoutEntityDisplayInterface.php
@@ -3,7 +3,7 @@
 namespace Drupal\layout_builder\Entity;
 
 use Drupal\Core\Entity\Display\EntityDisplayInterface;
-use Drupal\layout_builder\SectionStorageInterface;
+use Drupal\layout_builder\SectionListInterface;
 
 /**
  * Provides an interface for entity displays that have layout.
@@ -13,7 +13,7 @@
  *   experimental modules and development releases of contributed modules.
  *   See https://www.drupal.org/core/experimental for more information.
  */
-interface LayoutEntityDisplayInterface extends EntityDisplayInterface, SectionStorageInterface {
+interface LayoutEntityDisplayInterface extends EntityDisplayInterface, SectionListInterface {
 
   /**
    * Determines if the display allows custom overrides.
diff --git a/core/modules/layout_builder/src/Field/LayoutSectionItemList.php b/core/modules/layout_builder/src/Field/LayoutSectionItemList.php
index f67f90eba446fd230b5bb0608d3746d21148b002..a2ceca1373819bc00c91a9d323385c8e5cab1b45 100644
--- a/core/modules/layout_builder/src/Field/LayoutSectionItemList.php
+++ b/core/modules/layout_builder/src/Field/LayoutSectionItemList.php
@@ -3,13 +3,8 @@
 namespace Drupal\layout_builder\Field;
 
 use Drupal\Core\Field\FieldItemList;
-use Drupal\Core\Plugin\Context\Context;
-use Drupal\Core\Plugin\Context\ContextDefinition;
-use Drupal\Core\StringTranslation\TranslatableMarkup;
-use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
-use Drupal\layout_builder\OverridesSectionStorageInterface;
-use Drupal\layout_builder\Section;
-use Drupal\layout_builder\SectionStorageInterface;
+use Drupal\layout_builder\SectionListInterface;
+use Drupal\layout_builder\SectionStorage\SectionStorageTrait;
 
 /**
  * Defines a item list class for layout section fields.
@@ -18,35 +13,9 @@
  *
  * @see \Drupal\layout_builder\Plugin\Field\FieldType\LayoutSectionItem
  */
-class LayoutSectionItemList extends FieldItemList implements SectionStorageInterface, OverridesSectionStorageInterface {
+class LayoutSectionItemList extends FieldItemList implements SectionListInterface {
 
-  /**
-   * {@inheritdoc}
-   */
-  public function insertSection($delta, Section $section) {
-    if ($this->get($delta)) {
-      /** @var \Drupal\layout_builder\Plugin\Field\FieldType\LayoutSectionItem $item */
-      $item = $this->createItem($delta);
-      $item->section = $section;
-
-      // @todo Use https://www.drupal.org/node/66183 once resolved.
-      $start = array_slice($this->list, 0, $delta);
-      $end = array_slice($this->list, $delta);
-      $this->list = array_merge($start, [$item], $end);
-    }
-    else {
-      $this->appendSection($section);
-    }
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function appendSection(Section $section) {
-    $this->appendItem()->section = $section;
-    return $this;
-  }
+  use SectionStorageTrait;
 
   /**
    * {@inheritdoc}
@@ -63,84 +32,18 @@ public function getSections() {
   /**
    * {@inheritdoc}
    */
-  public function getSection($delta) {
+  protected function setSections(array $sections) {
+    $this->list = [];
+    $sections = array_values($sections);
     /** @var \Drupal\layout_builder\Plugin\Field\FieldType\LayoutSectionItem $item */
-    if (!$item = $this->get($delta)) {
-      throw new \OutOfBoundsException(sprintf('Invalid delta "%s" for the "%s" entity', $delta, $this->getEntity()->label()));
+    foreach ($sections as $section) {
+      $item = $this->appendItem();
+      $item->section = $section;
     }
 
-    return $item->section;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function removeSection($delta) {
-    $this->removeItem($delta);
     return $this;
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getContexts() {
-    $entity = $this->getEntity();
-    // @todo Use EntityContextDefinition after resolving
-    //   https://www.drupal.org/node/2932462.
-    $contexts['layout_builder.entity'] = new Context(new ContextDefinition("entity:{$entity->getEntityTypeId()}", new TranslatableMarkup('@entity being viewed', ['@entity' => $entity->getEntityType()->getLabel()])), $entity);
-    return $contexts;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function getStorageType() {
-    return 'overrides';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getStorageId() {
-    $entity = $this->getEntity();
-    return $entity->getEntityTypeId() . ':' . $entity->id();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function label() {
-    return $this->getEntity()->label();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function save() {
-    return $this->getEntity()->save();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCanonicalUrl() {
-    return $this->getEntity()->toUrl('canonical');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getLayoutBuilderUrl() {
-    return $this->getEntity()->toUrl('layout-builder');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getDefaultSectionStorage() {
-    return LayoutBuilderEntityViewDisplay::collectRenderDisplay($this->getEntity(), 'default');
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/layout_builder/src/Form/LayoutBuilderEntityViewDisplayForm.php b/core/modules/layout_builder/src/Form/LayoutBuilderEntityViewDisplayForm.php
index b2eb700d350e36cce96f30bdd52ddf8dad415649..63ec398eec25a73404447aa177a70a01232151a7 100644
--- a/core/modules/layout_builder/src/Form/LayoutBuilderEntityViewDisplayForm.php
+++ b/core/modules/layout_builder/src/Form/LayoutBuilderEntityViewDisplayForm.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\field_ui\Form\EntityViewDisplayEditForm;
 use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
+use Drupal\layout_builder\SectionStorageInterface;
 
 /**
  * Edit form for the LayoutBuilderEntityViewDisplay entity type.
@@ -24,6 +25,21 @@ class LayoutBuilderEntityViewDisplayForm extends EntityViewDisplayEditForm {
    */
   protected $entity;
 
+  /**
+   * The storage section.
+   *
+   * @var \Drupal\layout_builder\SectionStorageInterface
+   */
+  protected $sectionStorage;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL) {
+    $this->sectionStorage = $section_storage;
+    return parent::buildForm($form, $form_state);
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -40,7 +56,7 @@ public function form(array $form, FormStateInterface $form_state) {
       '#title' => $this->t('Manage layout'),
       '#weight' => -10,
       '#attributes' => ['class' => ['button']],
-      '#url' => $this->entity->getLayoutBuilderUrl(),
+      '#url' => $this->sectionStorage->getLayoutBuilderUrl(),
     ];
 
     // @todo Expand to work for all view modes in
diff --git a/core/modules/layout_builder/src/OverridesSectionStorageInterface.php b/core/modules/layout_builder/src/OverridesSectionStorageInterface.php
index 0d6fd2b05645cb74f7619b4633dd9947b10b26dd..76e15b5a1aef7ca5db67e80ed8b96d8220569c19 100644
--- a/core/modules/layout_builder/src/OverridesSectionStorageInterface.php
+++ b/core/modules/layout_builder/src/OverridesSectionStorageInterface.php
@@ -10,7 +10,7 @@
  *   experimental modules and development releases of contributed modules.
  *   See https://www.drupal.org/core/experimental for more information.
  */
-interface OverridesSectionStorageInterface {
+interface OverridesSectionStorageInterface extends SectionStorageInterface {
 
   /**
    * Returns the corresponding defaults section storage for this override.
diff --git a/core/modules/layout_builder/src/Plugin/Derivative/LayoutBuilderLocalTaskDeriver.php b/core/modules/layout_builder/src/Plugin/Derivative/LayoutBuilderLocalTaskDeriver.php
index 94160a7736f5d3b1f31cdcfb0cb0663fde74a850..c2046c0fd407170ab26a48d02c47b8f201bd9960 100644
--- a/core/modules/layout_builder/src/Plugin/Derivative/LayoutBuilderLocalTaskDeriver.php
+++ b/core/modules/layout_builder/src/Plugin/Derivative/LayoutBuilderLocalTaskDeriver.php
@@ -52,59 +52,52 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
   public function getDerivativeDefinitions($base_plugin_definition) {
     foreach ($this->getEntityTypes() as $entity_type_id => $entity_type) {
       // Overrides.
-      $this->derivatives["entity.$entity_type_id.layout_builder"] = $base_plugin_definition + [
-        'route_name' => "entity.$entity_type_id.layout_builder",
+      $this->derivatives["layout_builder.overrides.$entity_type_id.view"] = $base_plugin_definition + [
+        'route_name' => "layout_builder.overrides.$entity_type_id.view",
         'weight' => 15,
         'title' => $this->t('Layout'),
         'base_route' => "entity.$entity_type_id.canonical",
-        'entity_type_id' => $entity_type_id,
         'cache_contexts' => ['layout_builder_is_active:' . $entity_type_id],
       ];
-      $this->derivatives["entity.$entity_type_id.layout_builder_save"] = $base_plugin_definition + [
-        'route_name' => "entity.$entity_type_id.layout_builder_save",
+      $this->derivatives["layout_builder.overrides.$entity_type_id.save"] = $base_plugin_definition + [
+        'route_name' => "layout_builder.overrides.$entity_type_id.save",
         'title' => $this->t('Save Layout'),
-        'parent_id' => "layout_builder_ui:entity.$entity_type_id.layout_builder",
-        'entity_type_id' => $entity_type_id,
+        'parent_id' => "layout_builder_ui:layout_builder.overrides.$entity_type_id.view",
         'cache_contexts' => ['layout_builder_is_active:' . $entity_type_id],
       ];
-      $this->derivatives["entity.$entity_type_id.layout_builder_cancel"] = $base_plugin_definition + [
-        'route_name' => "entity.$entity_type_id.layout_builder_cancel",
+      $this->derivatives["layout_builder.overrides.$entity_type_id.cancel"] = $base_plugin_definition + [
+        'route_name' => "layout_builder.overrides.$entity_type_id.cancel",
         'title' => $this->t('Cancel Layout'),
-        'parent_id' => "layout_builder_ui:entity.$entity_type_id.layout_builder",
-        'entity_type_id' => $entity_type_id,
+        'parent_id' => "layout_builder_ui:layout_builder.overrides.$entity_type_id.view",
         'weight' => 5,
         'cache_contexts' => ['layout_builder_is_active:' . $entity_type_id],
       ];
       // @todo This link should be conditionally displayed, see
       //   https://www.drupal.org/node/2917777.
-      $this->derivatives["entity.$entity_type_id.layout_builder_revert"] = $base_plugin_definition + [
-        'route_name' => "entity.$entity_type_id.layout_builder_revert",
+      $this->derivatives["layout_builder.overrides.$entity_type_id.revert"] = $base_plugin_definition + [
+        'route_name' => "layout_builder.overrides.$entity_type_id.revert",
         'title' => $this->t('Revert to defaults'),
-        'parent_id' => "layout_builder_ui:entity.$entity_type_id.layout_builder",
-        'entity_type_id' => $entity_type_id,
+        'parent_id' => "layout_builder_ui:layout_builder.overrides.$entity_type_id.view",
         'weight' => 10,
         'cache_contexts' => ['layout_builder_is_active:' . $entity_type_id],
       ];
 
       // Defaults.
-      $this->derivatives["entity.entity_view_display.$entity_type_id.layout_builder"] = $base_plugin_definition + [
-        'route_name' => "entity.entity_view_display.$entity_type_id.layout_builder",
+      $this->derivatives["layout_builder.defaults.$entity_type_id.view"] = $base_plugin_definition + [
+        'route_name' => "layout_builder.defaults.$entity_type_id.view",
         'title' => $this->t('Manage layout'),
-        'base_route' => "entity.entity_view_display.$entity_type_id.layout_builder",
-        'entity_type_id' => $entity_type_id,
+        'base_route' => "layout_builder.defaults.$entity_type_id.view",
       ];
-      $this->derivatives["entity.entity_view_display.$entity_type_id.layout_builder_save"] = $base_plugin_definition + [
-        'route_name' => "entity.entity_view_display.$entity_type_id.layout_builder_save",
+      $this->derivatives["layout_builder.defaults.$entity_type_id.save"] = $base_plugin_definition + [
+        'route_name' => "layout_builder.defaults.$entity_type_id.save",
         'title' => $this->t('Save Layout'),
-        'parent_id' => "layout_builder_ui:entity.entity_view_display.$entity_type_id.layout_builder",
-        'entity_type_id' => $entity_type_id,
+        'parent_id' => "layout_builder_ui:layout_builder.defaults.$entity_type_id.view",
       ];
-      $this->derivatives["entity.entity_view_display.$entity_type_id.layout_builder_cancel"] = $base_plugin_definition + [
-        'route_name' => "entity.entity_view_display.$entity_type_id.layout_builder_cancel",
+      $this->derivatives["layout_builder.defaults.$entity_type_id.cancel"] = $base_plugin_definition + [
+        'route_name' => "layout_builder.defaults.$entity_type_id.cancel",
         'title' => $this->t('Cancel Layout'),
         'weight' => 5,
-        'parent_id' => "layout_builder_ui:entity.entity_view_display.$entity_type_id.layout_builder",
-        'entity_type_id' => $entity_type_id,
+        'parent_id' => "layout_builder_ui:layout_builder.defaults.$entity_type_id.view",
       ];
     }
 
diff --git a/core/modules/layout_builder/src/Plugin/SectionStorage/DefaultsSectionStorage.php b/core/modules/layout_builder/src/Plugin/SectionStorage/DefaultsSectionStorage.php
new file mode 100644
index 0000000000000000000000000000000000000000..a83ca049f54db6188d835d7215811a1d00d408b5
--- /dev/null
+++ b/core/modules/layout_builder/src/Plugin/SectionStorage/DefaultsSectionStorage.php
@@ -0,0 +1,295 @@
+<?php
+
+namespace Drupal\layout_builder\Plugin\SectionStorage;
+
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Plugin\Context\Context;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\Core\Url;
+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;
+
+/**
+ * Defines the 'defaults' section storage type.
+ *
+ * @SectionStorage(
+ *   id = "defaults",
+ * )
+ *
+ * @internal
+ *   Layout Builder is currently experimental and should only be leveraged by
+ *   experimental modules and development releases of contributed modules.
+ *   See https://www.drupal.org/core/experimental for more information.
+ */
+class DefaultsSectionStorage extends SectionStorageBase implements ContainerFactoryPluginInterface, DefaultsSectionStorageInterface {
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * The entity type bundle info.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
+   */
+  protected $entityTypeBundleInfo;
+
+  /**
+   * {@inheritdoc}
+   *
+   * @var \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface
+   */
+  protected $sectionList;
+
+  /**
+   * The sample entity generator.
+   *
+   * @var \Drupal\layout_builder\Entity\LayoutBuilderSampleEntityGenerator
+   */
+  protected $sampleEntityGenerator;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, LayoutBuilderSampleEntityGenerator $sample_entity_generator) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->entityTypeManager = $entity_type_manager;
+    $this->entityTypeBundleInfo = $entity_type_bundle_info;
+    $this->sampleEntityGenerator = $sample_entity_generator;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity_type.manager'),
+      $container->get('entity_type.bundle.info'),
+      $container->get('layout_builder.sample_entity_generator')
+    );
+  }
+
+  /**
+   * {@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);
+  }
+
+  /**
+   * Gets the entity storing the overrides.
+   *
+   * @return \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface
+   *   The entity storing the defaults.
+   */
+  protected function getDisplay() {
+    return $this->getSectionList();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getStorageId() {
+    return $this->getDisplay()->id();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRedirectUrl() {
+    return Url::fromRoute("entity.entity_view_display.{$this->getDisplay()->getTargetEntityTypeId()}.view_mode", $this->getRouteParameters());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLayoutBuilderUrl() {
+    return Url::fromRoute("layout_builder.{$this->getStorageType()}.{$this->getDisplay()->getTargetEntityTypeId()}.view", $this->getRouteParameters());
+  }
+
+  /**
+   * Provides the route parameters needed to generate a URL for this object.
+   *
+   * @return mixed[]
+   *   An associative array of parameter names and values.
+   */
+  protected function getRouteParameters() {
+    $display = $this->getDisplay();
+    $entity_type = $this->entityTypeManager->getDefinition($display->getTargetEntityTypeId());
+    $route_parameters = FieldUI::getRouteBundleParameter($entity_type, $display->getTargetBundle());
+    $route_parameters['view_mode_name'] = $display->getMode();
+    return $route_parameters;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildRoutes(RouteCollection $collection) {
+    foreach ($this->getEntityTypes() as $entity_type_id => $entity_type) {
+      // Try to get the route from the current collection.
+      if (!$entity_route = $collection->get($entity_type->get('field_ui_base_route'))) {
+        continue;
+      }
+
+      $path = $entity_route->getPath() . '/display-layout/{view_mode_name}';
+
+      $defaults = [];
+      $defaults['entity_type_id'] = $entity_type_id;
+      // If the entity type has no bundles and it doesn't use {bundle} in its
+      // admin path, use the entity type.
+      if (strpos($path, '{bundle}') === FALSE) {
+        if (!$entity_type->hasKey('bundle')) {
+          $defaults['bundle'] = $entity_type_id;
+        }
+        else {
+          $defaults['bundle_key'] = $entity_type->getBundleEntityType();
+        }
+      }
+
+      $requirements = [];
+      $requirements['_field_ui_view_mode_access'] = 'administer ' . $entity_type_id . ' display';
+
+      $options = $entity_route->getOptions();
+      $options['_admin_route'] = FALSE;
+
+      $this->buildLayoutRoutes($collection, $this->getPluginDefinition(), $path, $defaults, $requirements, $options, $entity_type_id);
+
+      $route_names = [
+        "entity.entity_view_display.{$entity_type_id}.default",
+        "entity.entity_view_display.{$entity_type_id}.view_mode",
+      ];
+      foreach ($route_names as $route_name) {
+        if (!$route = $collection->get($route_name)) {
+          continue;
+        }
+
+        $route->addDefaults([
+          'section_storage_type' => $this->getStorageType(),
+          'section_storage' => '',
+        ] + $defaults);
+        $parameters['section_storage']['layout_builder_tempstore'] = TRUE;
+        $parameters = NestedArray::mergeDeep($parameters, $route->getOption('parameters') ?: []);
+        $route->setOption('parameters', $parameters);
+      }
+    }
+  }
+
+  /**
+   * Returns an array of relevant entity types.
+   *
+   * @return \Drupal\Core\Entity\EntityTypeInterface[]
+   *   An array of entity types.
+   */
+  protected function getEntityTypes() {
+    return array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $entity_type) {
+      return $entity_type->hasLinkTemplate('layout-builder') && $entity_type->get('field_ui_base_route');
+    });
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function extractIdFromRoute($value, $definition, $name, array $defaults) {
+    if (is_string($value) && strpos($value, '.') !== FALSE) {
+      return $value;
+    }
+
+    // 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'];
+    }
+  }
+
+  /**
+   * {@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()));
+    }
+
+    $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);
+      $display = $storage->create([
+        'targetEntityType' => $entity_type_id,
+        'bundle' => $bundle,
+        'mode' => $view_mode,
+        'status' => TRUE,
+      ]);
+    }
+    return $display;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getContexts() {
+    $display = $this->getDisplay();
+    $entity = $this->sampleEntityGenerator->get($display->getTargetEntityTypeId(), $display->getTargetBundle());
+    $context_label = new TranslatableMarkup('@entity being viewed', ['@entity' => $entity->getEntityType()->getLabel()]);
+
+    // @todo Use EntityContextDefinition after resolving
+    //   https://www.drupal.org/node/2932462.
+    $contexts = [];
+    $contexts['layout_builder.entity'] = new Context(new ContextDefinition("entity:{$entity->getEntityTypeId()}", $context_label), $entity);
+    return $contexts;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function label() {
+    return $this->getDisplay()->label();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save() {
+    return $this->getDisplay()->save();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isOverridable() {
+    return $this->getDisplay()->isOverridable();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setOverridable($overridable = TRUE) {
+    $this->getDisplay()->setOverridable($overridable);
+    return $this;
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php b/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php
new file mode 100644
index 0000000000000000000000000000000000000000..58adb5503d256dcc41dd4600b6e753295b74ed1d
--- /dev/null
+++ b/core/modules/layout_builder/src/Plugin/SectionStorage/OverridesSectionStorage.php
@@ -0,0 +1,234 @@
+<?php
+
+namespace Drupal\layout_builder\Plugin\SectionStorage;
+
+use Drupal\Core\Entity\EntityFieldManagerInterface;
+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\Context;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+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;
+
+/**
+ * Defines the 'overrides' section storage type.
+ *
+ * @SectionStorage(
+ *   id = "overrides",
+ * )
+ *
+ * @internal
+ *   Layout Builder is currently experimental and should only be leveraged by
+ *   experimental modules and development releases of contributed modules.
+ *   See https://www.drupal.org/core/experimental for more information.
+ */
+class OverridesSectionStorage extends SectionStorageBase implements ContainerFactoryPluginInterface, OverridesSectionStorageInterface {
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * The entity field manager.
+   *
+   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
+   */
+  protected $entityFieldManager;
+
+  /**
+   * {@inheritdoc}
+   *
+   * @var \Drupal\layout_builder\SectionListInterface|\Drupal\Core\Field\FieldItemListInterface
+   */
+  protected $sectionList;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->entityTypeManager = $entity_type_manager;
+    $this->entityFieldManager = $entity_field_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity_type.manager'),
+      $container->get('entity_field.manager')
+    );
+  }
+
+  /**
+   * {@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);
+  }
+
+  /**
+   * Gets the entity storing the overrides.
+   *
+   * @return \Drupal\Core\Entity\FieldableEntityInterface
+   *   The entity storing the overrides.
+   */
+  protected function getEntity() {
+    return $this->getSectionList()->getEntity();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getStorageId() {
+    $entity = $this->getEntity();
+    return $entity->getEntityTypeId() . '.' . $entity->id();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function extractIdFromRoute($value, $definition, $name, array $defaults) {
+    if (strpos($value, '.') !== FALSE) {
+      return $value;
+    }
+
+    if (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;
+    }
+  }
+
+  /**
+   * {@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');
+      }
+    }
+    throw new \InvalidArgumentException(sprintf('The "%s" ID for the "%s" section storage type is invalid', $id, $this->getStorageType()));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildRoutes(RouteCollection $collection) {
+    foreach ($this->getEntityTypes() as $entity_type_id => $entity_type) {
+      $defaults = [];
+      $defaults['entity_type_id'] = $entity_type_id;
+
+      $requirements = [];
+      if ($this->hasIntegerId($entity_type)) {
+        $requirements[$entity_type_id] = '\d+';
+      }
+
+      $options = [];
+      // Ensure that upcasting is run in the correct order.
+      $options['parameters']['section_storage'] = [];
+      $options['parameters'][$entity_type_id]['type'] = 'entity:' . $entity_type_id;
+
+      $template = $entity_type->getLinkTemplate('layout-builder');
+      $this->buildLayoutRoutes($collection, $this->getPluginDefinition(), $template, $defaults, $requirements, $options, $entity_type_id);
+    }
+  }
+
+  /**
+   * Determines if this entity type's ID is stored as an integer.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   An entity type.
+   *
+   * @return bool
+   *   TRUE if this entity type's ID key is always an integer, FALSE otherwise.
+   */
+  protected function hasIntegerId(EntityTypeInterface $entity_type) {
+    $field_storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($entity_type->id());
+    return $field_storage_definitions[$entity_type->getKey('id')]->getType() === 'integer';
+  }
+
+  /**
+   * Returns an array of relevant entity types.
+   *
+   * @return \Drupal\Core\Entity\EntityTypeInterface[]
+   *   An array of entity types.
+   */
+  protected function getEntityTypes() {
+    return array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $entity_type) {
+      return $entity_type->hasLinkTemplate('layout-builder');
+    });
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefaultSectionStorage() {
+    return LayoutBuilderEntityViewDisplay::collectRenderDisplay($this->getEntity(), 'default');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRedirectUrl() {
+    return $this->getEntity()->toUrl('canonical');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLayoutBuilderUrl() {
+    $entity = $this->getEntity();
+    $route_parameters[$entity->getEntityTypeId()] = $entity->id();
+    return Url::fromRoute("layout_builder.{$this->getStorageType()}.{$this->getEntity()->getEntityTypeId()}.view", $route_parameters);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getContexts() {
+    $entity = $this->getEntity();
+    // @todo Use EntityContextDefinition after resolving
+    //   https://www.drupal.org/node/2932462.
+    $contexts['layout_builder.entity'] = new Context(new ContextDefinition("entity:{$entity->getEntityTypeId()}", new TranslatableMarkup('@entity being viewed', ['@entity' => $entity->getEntityType()->getLabel()])), $entity);
+    return $contexts;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function label() {
+    return $this->getEntity()->label();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save() {
+    return $this->getEntity()->save();
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Plugin/SectionStorage/SectionStorageBase.php b/core/modules/layout_builder/src/Plugin/SectionStorage/SectionStorageBase.php
new file mode 100644
index 0000000000000000000000000000000000000000..c419060c45b8ac068a63ae13f5cc118a42a2302d
--- /dev/null
+++ b/core/modules/layout_builder/src/Plugin/SectionStorage/SectionStorageBase.php
@@ -0,0 +1,106 @@
+<?php
+
+namespace Drupal\layout_builder\Plugin\SectionStorage;
+
+use Drupal\Core\Plugin\PluginBase;
+use Drupal\layout_builder\Routing\LayoutBuilderRoutesTrait;
+use Drupal\layout_builder\Section;
+use Drupal\layout_builder\SectionListInterface;
+use Drupal\layout_builder\SectionStorageInterface;
+
+/**
+ * Provides a base class for Section Storage types.
+ *
+ * @internal
+ *   Layout Builder is currently experimental and should only be leveraged by
+ *   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 {
+
+  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;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getStorageType() {
+    return $this->getPluginId();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function count() {
+    return $this->getSectionList()->count();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSections() {
+    return $this->getSectionList()->getSections();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSection($delta) {
+    return $this->getSectionList()->getSection($delta);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function appendSection(Section $section) {
+    $this->getSectionList()->appendSection($section);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function insertSection($delta, Section $section) {
+    $this->getSectionList()->insertSection($delta, $section);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function removeSection($delta) {
+    $this->getSectionList()->removeSection($delta);
+    return $this;
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Routing/LayoutBuilderRoutes.php b/core/modules/layout_builder/src/Routing/LayoutBuilderRoutes.php
index 500a380a11bed717b2a7be6f30fc2ccbe1c03b0a..1046579458e0ff14bf10b552d6bb9e4feeded769 100644
--- a/core/modules/layout_builder/src/Routing/LayoutBuilderRoutes.php
+++ b/core/modules/layout_builder/src/Routing/LayoutBuilderRoutes.php
@@ -2,14 +2,9 @@
 
 namespace Drupal\layout_builder\Routing;
 
-use Drupal\Component\Utility\NestedArray;
-use Drupal\Core\Entity\EntityFieldManagerInterface;
-use Drupal\Core\Entity\EntityTypeInterface;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Routing\RouteBuildEvent;
 use Drupal\Core\Routing\RoutingEvents;
-use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
-use Drupal\layout_builder\Field\LayoutSectionItemList;
+use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 
 /**
@@ -19,61 +14,21 @@
  */
 class LayoutBuilderRoutes implements EventSubscriberInterface {
 
-  use LayoutBuilderRoutesTrait;
-
-  /**
-   * The entity type manager.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected $entityTypeManager;
-
   /**
-   * The entity field manager.
+   * The section storage manager.
    *
-   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
+   * @var \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface
    */
-  protected $entityFieldManager;
+  protected $sectionStorageManager;
 
   /**
    * Constructs a new LayoutBuilderRoutes.
    *
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
-   *   The entity type manager.
-   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
-   *   The entity field manager.
+   * @param \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface $section_storage_manager
+   *   The section storage manager.
    */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager) {
-    $this->entityTypeManager = $entity_type_manager;
-    $this->entityFieldManager = $entity_field_manager;
-  }
-
-  /**
-   * Generates layout builder routes.
-   *
-   * @return \Symfony\Component\Routing\Route[]
-   *   An array of route objects.
-   */
-  public function getRoutes() {
-    $routes = [];
-
-    foreach ($this->getEntityTypes() as $entity_type_id => $entity_type) {
-      $defaults = [];
-      $defaults['entity_type_id'] = $entity_type_id;
-
-      $requirements = [];
-      if ($this->hasIntegerId($entity_type)) {
-        $requirements[$entity_type_id] = '\d+';
-      }
-
-      $options = [];
-      $options['parameters']['section_storage']['layout_builder_tempstore'] = TRUE;
-      $options['parameters'][$entity_type_id]['type'] = 'entity:' . $entity_type_id;
-
-      $template = $entity_type->getLinkTemplate('layout-builder');
-      $routes += $this->buildRoute(LayoutSectionItemList::class, 'entity.' . $entity_type_id, $template, $defaults, $requirements, $options);
-    }
-    return $routes;
+  public function __construct(SectionStorageManagerInterface $section_storage_manager) {
+    $this->sectionStorageManager = $section_storage_manager;
   }
 
   /**
@@ -84,70 +39,11 @@ public function getRoutes() {
    */
   public function onAlterRoutes(RouteBuildEvent $event) {
     $collection = $event->getRouteCollection();
-    foreach ($this->getEntityTypes() as $entity_type_id => $entity_type) {
-      if ($route_name = $entity_type->get('field_ui_base_route')) {
-        // Try to get the route from the current collection.
-        if (!$entity_route = $collection->get($route_name)) {
-          continue;
-        }
-        $path = $entity_route->getPath() . '/display-layout/{view_mode_name}';
-
-        $defaults = [];
-        $defaults['entity_type_id'] = $entity_type_id;
-        // If the entity type has no bundles and it doesn't use {bundle} in its
-        // admin path, use the entity type.
-        if (strpos($path, '{bundle}') === FALSE) {
-          if (!$entity_type->hasKey('bundle')) {
-            $defaults['bundle'] = $entity_type_id;
-          }
-          else {
-            $defaults['bundle_key'] = $entity_type->getBundleEntityType();
-          }
-        }
-
-        $requirements = [];
-        $requirements['_field_ui_view_mode_access'] = 'administer ' . $entity_type_id . ' display';
-
-        $options['parameters']['section_storage']['layout_builder_tempstore'] = TRUE;
-        // Merge the entity route options in after Layout Builder's.
-        $options = NestedArray::mergeDeep($options, $entity_route->getOptions());
-        // Disable the admin route flag after merging in entity route options.
-        $options['_admin_route'] = FALSE;
-
-        $routes = $this->buildRoute(LayoutBuilderEntityViewDisplay::class, 'entity.entity_view_display.' . $entity_type_id, $path, $defaults, $requirements, $options);
-        foreach ($routes as $name => $route) {
-          $collection->add($name, $route);
-        }
-      }
+    foreach ($this->sectionStorageManager->getDefinitions() as $plugin_id => $definition) {
+      $this->sectionStorageManager->loadEmpty($plugin_id)->buildRoutes($collection);
     }
   }
 
-  /**
-   * Determines if this entity type's ID is stored as an integer.
-   *
-   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
-   *   An entity type.
-   *
-   * @return bool
-   *   TRUE if this entity type's ID key is always an integer, FALSE otherwise.
-   */
-  protected function hasIntegerId(EntityTypeInterface $entity_type) {
-    $field_storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($entity_type->id());
-    return $field_storage_definitions[$entity_type->getKey('id')]->getType() === 'integer';
-  }
-
-  /**
-   * Returns an array of relevant entity types.
-   *
-   * @return \Drupal\Core\Entity\EntityTypeInterface[]
-   *   An array of entity types.
-   */
-  protected function getEntityTypes() {
-    return array_filter($this->entityTypeManager->getDefinitions(), function (EntityTypeInterface $entity_type) {
-      return $entity_type->hasLinkTemplate('layout-builder');
-    });
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/layout_builder/src/Routing/LayoutBuilderRoutesTrait.php b/core/modules/layout_builder/src/Routing/LayoutBuilderRoutesTrait.php
index da9e1c1759f15ee632978856c97543778c2f0047..febedbe31efdc98b95e84a4565d0d06f7726c52a 100644
--- a/core/modules/layout_builder/src/Routing/LayoutBuilderRoutesTrait.php
+++ b/core/modules/layout_builder/src/Routing/LayoutBuilderRoutesTrait.php
@@ -2,9 +2,11 @@
 
 namespace Drupal\layout_builder\Routing;
 
+use Drupal\Component\Utility\NestedArray;
 use Drupal\layout_builder\OverridesSectionStorageInterface;
-use Drupal\layout_builder\SectionStorageInterface;
+use Drupal\layout_builder\SectionStorage\SectionStorageDefinition;
 use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
 
 /**
  * Provides a trait for building routes for a Layout Builder UI.
@@ -19,36 +21,41 @@ trait LayoutBuilderRoutesTrait {
   /**
    * Builds the layout routes for the given values.
    *
-   * @param string $class
-   *   The class defining the section storage.
-   * @param string $route_name_prefix
-   *   The prefix to use for the route name.
+   * @param \Symfony\Component\Routing\RouteCollection $collection
+   *   The route collection.
+   * @param \Drupal\layout_builder\SectionStorage\SectionStorageDefinition $definition
+   *   The definition of the section storage.
    * @param string $path
    *   The path patten for the routes.
    * @param array $defaults
-   *   An array of default parameter values.
+   *   (optional) An array of default parameter values.
    * @param array $requirements
-   *   An array of requirements for parameters.
+   *   (optional) An array of requirements for parameters.
    * @param array $options
-   *   An array of options.
-   *
-   * @return \Symfony\Component\Routing\Route[]
-   *   An array of route objects.
+   *   (optional) An array of options.
+   * @param string $route_name_prefix
+   *   (optional) The prefix to use for the route name.
    */
-  protected function buildRoute($class, $route_name_prefix, $path, array $defaults, array $requirements, array $options) {
-    $routes = [];
-
-    if (!is_subclass_of($class, SectionStorageInterface::class)) {
-      return $routes;
-    }
-
-    $defaults['section_storage_type'] = $class::getStorageType();
+  protected function buildLayoutRoutes(RouteCollection $collection, SectionStorageDefinition $definition, $path, array $defaults = [], array $requirements = [], array $options = [], $route_name_prefix = '') {
+    $type = $definition->id();
+    $defaults['section_storage_type'] = $type;
     // Provide an empty value to allow the section storage to be upcast.
     $defaults['section_storage'] = '';
     // Trigger the layout builder access check.
     $requirements['_has_layout_section'] = 'true';
     // Trigger the layout builder RouteEnhancer.
     $options['_layout_builder'] = TRUE;
+    // Trigger the layout builder param converter.
+    $parameters['section_storage']['layout_builder_tempstore'] = TRUE;
+    // Merge the passed in options in after Layout Builder's parameters.
+    $options = NestedArray::mergeDeep(['parameters' => $parameters], $options);
+
+    if ($route_name_prefix) {
+      $route_name_prefix = "layout_builder.$type.$route_name_prefix";
+    }
+    else {
+      $route_name_prefix = "layout_builder.$type";
+    }
 
     $main_defaults = $defaults;
     $main_defaults['is_rebuilding'] = FALSE;
@@ -58,7 +65,7 @@ protected function buildRoute($class, $route_name_prefix, $path, array $defaults
       ->setDefaults($main_defaults)
       ->setRequirements($requirements)
       ->setOptions($options);
-    $routes["{$route_name_prefix}.layout_builder"] = $route;
+    $collection->add("$route_name_prefix.view", $route);
 
     $save_defaults = $defaults;
     $save_defaults['_controller'] = '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout';
@@ -66,7 +73,7 @@ protected function buildRoute($class, $route_name_prefix, $path, array $defaults
       ->setDefaults($save_defaults)
       ->setRequirements($requirements)
       ->setOptions($options);
-    $routes["{$route_name_prefix}.layout_builder_save"] = $route;
+    $collection->add("$route_name_prefix.save", $route);
 
     $cancel_defaults = $defaults;
     $cancel_defaults['_controller'] = '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout';
@@ -74,19 +81,17 @@ protected function buildRoute($class, $route_name_prefix, $path, array $defaults
       ->setDefaults($cancel_defaults)
       ->setRequirements($requirements)
       ->setOptions($options);
-    $routes["{$route_name_prefix}.layout_builder_cancel"] = $route;
+    $collection->add("$route_name_prefix.cancel", $route);
 
-    if (is_subclass_of($class, OverridesSectionStorageInterface::class)) {
+    if (is_subclass_of($definition->getClass(), OverridesSectionStorageInterface::class)) {
       $revert_defaults = $defaults;
       $revert_defaults['_form'] = '\Drupal\layout_builder\Form\RevertOverridesForm';
       $route = (new Route("$path/revert"))
         ->setDefaults($revert_defaults)
         ->setRequirements($requirements)
         ->setOptions($options);
-      $routes["{$route_name_prefix}.layout_builder_revert"] = $route;
+      $collection->add("$route_name_prefix.revert", $route);
     }
-
-    return $routes;
   }
 
 }
diff --git a/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php b/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php
index 228a786764d6c902d77d077d1114315b74022dc2..263b767f729871845c3d36c120752cf520e97e97 100644
--- a/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php
+++ b/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php
@@ -2,9 +2,9 @@
 
 namespace Drupal\layout_builder\Routing;
 
-use Drupal\Core\DependencyInjection\ClassResolverInterface;
 use Drupal\Core\ParamConverter\ParamConverterInterface;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
+use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -22,59 +22,33 @@ class LayoutTempstoreParamConverter implements ParamConverterInterface {
   protected $layoutTempstoreRepository;
 
   /**
-   * The class resolver.
+   * The section storage manager.
    *
-   * @var \Drupal\Core\DependencyInjection\ClassResolverInterface
+   * @var \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface
    */
-  protected $classResolver;
+  protected $sectionStorageManager;
 
   /**
    * Constructs a new LayoutTempstoreParamConverter.
    *
    * @param \Drupal\layout_builder\LayoutTempstoreRepositoryInterface $layout_tempstore_repository
    *   The layout tempstore repository.
-   * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
-   *   The class resolver.
+   * @param \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface $section_storage_manager
+   *   The section storage manager.
    */
-  public function __construct(LayoutTempstoreRepositoryInterface $layout_tempstore_repository, ClassResolverInterface $class_resolver) {
+  public function __construct(LayoutTempstoreRepositoryInterface $layout_tempstore_repository, SectionStorageManagerInterface $section_storage_manager) {
     $this->layoutTempstoreRepository = $layout_tempstore_repository;
-    $this->classResolver = $class_resolver;
+    $this->sectionStorageManager = $section_storage_manager;
   }
 
   /**
    * {@inheritdoc}
    */
   public function convert($value, $definition, $name, array $defaults) {
-    if ($converter = $this->getParamConverterFromDefaults($defaults)) {
-      if ($object = $converter->convert($value, $definition, $name, $defaults)) {
-        // Pass the result of the storage param converter through the
-        // tempstore repository.
-        return $this->layoutTempstoreRepository->get($object);
-      }
-    }
-  }
-
-  /**
-   * Gets a param converter based on the provided defaults.
-   *
-   * @param array $defaults
-   *   The route defaults array.
-   *
-   * @return \Drupal\layout_builder\Routing\SectionStorageParamConverterInterface|null
-   *   A section storage param converter if found, NULL otherwise.
-   */
-  protected function getParamConverterFromDefaults(array $defaults) {
-    // If a storage type was specified, get the corresponding param converter.
-    if (isset($defaults['section_storage_type'])) {
-      try {
-        $converter = $this->classResolver->getInstanceFromDefinition('layout_builder.section_storage_param_converter.' . $defaults['section_storage_type']);
-      }
-      catch (\InvalidArgumentException $e) {
-        $converter = NULL;
-      }
-
-      if ($converter instanceof SectionStorageParamConverterInterface) {
-        return $converter;
+    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);
       }
     }
   }
diff --git a/core/modules/layout_builder/src/Routing/SectionStorageDefaultsParamConverter.php b/core/modules/layout_builder/src/Routing/SectionStorageDefaultsParamConverter.php
deleted file mode 100644
index 2f886102c3e7f8786530ca032ce930711789378d..0000000000000000000000000000000000000000
--- a/core/modules/layout_builder/src/Routing/SectionStorageDefaultsParamConverter.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-namespace Drupal\layout_builder\Routing;
-
-use Drupal\Core\ParamConverter\EntityConverter;
-
-/**
- * Provides a param converter for defaults-based section storage.
- *
- * @internal
- *   Layout Builder is currently experimental and should only be leveraged by
- *   experimental modules and development releases of contributed modules.
- *   See https://www.drupal.org/core/experimental for more information.
- */
-class SectionStorageDefaultsParamConverter extends EntityConverter implements SectionStorageParamConverterInterface {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function convert($value, $definition, $name, array $defaults) {
-    if (!$value) {
-      // 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 NULL;
-      }
-
-      $value = $defaults['entity_type_id'] . '.' . $defaults['bundle'] . '.' . $defaults['view_mode_name'];
-    }
-    if (!$display = parent::convert($value, $definition, $name, $defaults)) {
-      list($entity_type_id, $bundle, $view_mode) = explode('.', $value);
-      $display = $this->entityManager->getStorage('entity_view_display')->create([
-        'targetEntityType' => $entity_type_id,
-        'bundle' => $bundle,
-        'mode' => $view_mode,
-        'status' => TRUE,
-      ]);
-    }
-    return $display;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function getEntityTypeFromDefaults($definition, $name, array $defaults) {
-    return 'entity_view_display';
-  }
-
-}
diff --git a/core/modules/layout_builder/src/Routing/SectionStorageOverridesParamConverter.php b/core/modules/layout_builder/src/Routing/SectionStorageOverridesParamConverter.php
deleted file mode 100644
index 8d8ae58059fba94c7b16f16bd3f091a7bd2d8939..0000000000000000000000000000000000000000
--- a/core/modules/layout_builder/src/Routing/SectionStorageOverridesParamConverter.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-
-namespace Drupal\layout_builder\Routing;
-
-use Drupal\Core\Entity\FieldableEntityInterface;
-use Drupal\Core\ParamConverter\EntityConverter;
-
-/**
- * Provides a param converter for overrides-based section storage.
- */
-class SectionStorageOverridesParamConverter extends EntityConverter implements SectionStorageParamConverterInterface {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function convert($value, $definition, $name, array $defaults) {
-    $entity_id = $this->getEntityIdFromDefaults($value, $defaults);
-    $entity_type_id = $this->getEntityTypeFromDefaults($definition, $name, $defaults);
-    if (!$entity_id || !$entity_type_id) {
-      return NULL;
-    }
-
-    $entity = parent::convert($entity_id, $definition, $name, $defaults);
-    if ($entity instanceof FieldableEntityInterface && $entity->hasField('layout_builder__layout')) {
-      return $entity->get('layout_builder__layout');
-    }
-  }
-
-  /**
-   * Determines the entity ID given a parameter value and route defaults.
-   *
-   * @param string $value
-   *   The parameter value.
-   * @param array $defaults
-   *   The route defaults array.
-   *
-   * @return string|null
-   *   The entity ID if it exists, NULL otherwise.
-   */
-  protected function getEntityIdFromDefaults($value, array $defaults) {
-    $entity_id = NULL;
-    // Layout Builder routes will have this parameter in the form of
-    // 'entity_type_id:entity_id'.
-    if (strpos($value, ':') !== FALSE) {
-      list(, $entity_id) = explode(':', $value);
-    }
-    // Overridden routes have the entity ID available in the defaults.
-    elseif (isset($defaults['entity_type_id']) && !empty($defaults[$defaults['entity_type_id']])) {
-      $entity_id = $defaults[$defaults['entity_type_id']];
-    }
-    return $entity_id;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function getEntityTypeFromDefaults($definition, $name, array $defaults) {
-    // Layout Builder routes will have this parameter in the form of
-    // 'entity_type_id:entity_id'.
-    if (isset($defaults[$name]) && strpos($defaults[$name], ':') !== FALSE) {
-      list($entity_type_id) = explode(':', $defaults[$name], 2);
-      return $entity_type_id;
-    }
-    // Overridden routes have the entity type ID available in the defaults.
-    elseif (isset($defaults['entity_type_id'])) {
-      return $defaults['entity_type_id'];
-    }
-  }
-
-}
diff --git a/core/modules/layout_builder/src/Routing/SectionStorageParamConverterInterface.php b/core/modules/layout_builder/src/Routing/SectionStorageParamConverterInterface.php
deleted file mode 100644
index 955b6735132205d68f1a7b416cacc54e0c208f4a..0000000000000000000000000000000000000000
--- a/core/modules/layout_builder/src/Routing/SectionStorageParamConverterInterface.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-namespace Drupal\layout_builder\Routing;
-
-/**
- * Defines the interface of a param converter for section storage.
- *
- * A service implementing this interface must have a service ID prefixed with
- * 'layout_builder.section_storage_param_converter.', followed by the section
- * storage type.
- *
- * @see \Drupal\Core\ParamConverter\ParamConverterInterface
- * @see \Drupal\layout_builder\SectionStorageInterface::getStorageType()
- */
-interface SectionStorageParamConverterInterface {
-
-  /**
-   * Converts path variables to their corresponding objects.
-   *
-   * @param mixed $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.
-   *
-   * @return \Drupal\layout_builder\SectionStorageInterface|null
-   *   The section storage if it could be loaded, or NULL otherwise.
-   */
-  public function convert($value, $definition, $name, array $defaults);
-
-}
diff --git a/core/modules/layout_builder/src/SectionListInterface.php b/core/modules/layout_builder/src/SectionListInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..8df586a7aae6ec0f7becd8846234e16f582c3b15
--- /dev/null
+++ b/core/modules/layout_builder/src/SectionListInterface.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Drupal\layout_builder;
+
+/**
+ * Defines the interface for an object that stores layout sections.
+ *
+ * @internal
+ *   Layout Builder is currently experimental and should only be leveraged by
+ *   experimental modules and development releases of contributed modules.
+ *   See https://www.drupal.org/core/experimental for more information.
+ *
+ * @see \Drupal\layout_builder\Section
+ */
+interface SectionListInterface extends \Countable {
+
+  /**
+   * Gets the layout sections.
+   *
+   * @return \Drupal\layout_builder\Section[]
+   *   A sequentially and numerically keyed array of section objects.
+   */
+  public function getSections();
+
+  /**
+   * Gets a domain object for the layout section.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   *
+   * @return \Drupal\layout_builder\Section
+   *   The layout section.
+   */
+  public function getSection($delta);
+
+  /**
+   * Appends a new section to the end of the list.
+   *
+   * @param \Drupal\layout_builder\Section $section
+   *   The section to append.
+   *
+   * @return $this
+   */
+  public function appendSection(Section $section);
+
+  /**
+   * Inserts a new section at a given delta.
+   *
+   * If a section exists at the given index, the section at that position and
+   * others after it are shifted backward.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   * @param \Drupal\layout_builder\Section $section
+   *   The section to insert.
+   *
+   * @return $this
+   */
+  public function insertSection($delta, Section $section);
+
+  /**
+   * Removes the section at the given delta.
+   *
+   * As sections are stored sequentially and numerically this will re-key every
+   * subsequent section, shifting them forward.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   *
+   * @return $this
+   */
+  public function removeSection($delta);
+
+}
diff --git a/core/modules/layout_builder/src/SectionStorage/SectionStorageDefinition.php b/core/modules/layout_builder/src/SectionStorage/SectionStorageDefinition.php
new file mode 100644
index 0000000000000000000000000000000000000000..61b975a471825d53af63e6804d6696bf578f905b
--- /dev/null
+++ b/core/modules/layout_builder/src/SectionStorage/SectionStorageDefinition.php
@@ -0,0 +1,75 @@
+<?php
+
+namespace Drupal\layout_builder\SectionStorage;
+
+use Drupal\Component\Plugin\Definition\PluginDefinition;
+
+/**
+ * Provides section storage type plugin definition.
+ *
+ * @internal
+ *   Layout Builder is currently experimental and should only be leveraged by
+ *   experimental modules and development releases of contributed modules.
+ *   See https://www.drupal.org/core/experimental for more information.
+ */
+class SectionStorageDefinition extends PluginDefinition {
+
+  /**
+   * Any additional properties and values.
+   *
+   * @var array
+   */
+  protected $additional = [];
+
+  /**
+   * LayoutDefinition constructor.
+   *
+   * @param array $definition
+   *   An array of values from the annotation.
+   */
+  public function __construct(array $definition = []) {
+    foreach ($definition as $property => $value) {
+      $this->set($property, $value);
+    }
+  }
+
+  /**
+   * Gets any arbitrary property.
+   *
+   * @param string $property
+   *   The property to retrieve.
+   *
+   * @return mixed
+   *   The value for that property, or NULL if the property does not exist.
+   */
+  public function get($property) {
+    if (property_exists($this, $property)) {
+      $value = isset($this->{$property}) ? $this->{$property} : NULL;
+    }
+    else {
+      $value = isset($this->additional[$property]) ? $this->additional[$property] : NULL;
+    }
+    return $value;
+  }
+
+  /**
+   * Sets a value to an arbitrary property.
+   *
+   * @param string $property
+   *   The property to use for the value.
+   * @param mixed $value
+   *   The value to set.
+   *
+   * @return $this
+   */
+  public function set($property, $value) {
+    if (property_exists($this, $property)) {
+      $this->{$property} = $value;
+    }
+    else {
+      $this->additional[$property] = $value;
+    }
+    return $this;
+  }
+
+}
diff --git a/core/modules/layout_builder/src/SectionStorage/SectionStorageManager.php b/core/modules/layout_builder/src/SectionStorage/SectionStorageManager.php
new file mode 100644
index 0000000000000000000000000000000000000000..18147cd1d8157ead6499c8d20c74cb4a387e57b4
--- /dev/null
+++ b/core/modules/layout_builder/src/SectionStorage/SectionStorageManager.php
@@ -0,0 +1,71 @@
+<?php
+
+namespace Drupal\layout_builder\SectionStorage;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\layout_builder\Annotation\SectionStorage;
+use Drupal\layout_builder\SectionStorageInterface;
+
+/**
+ * Provides the Section Storage type plugin manager.
+ *
+ * @internal
+ *   Layout Builder is currently experimental and should only be leveraged by
+ *   experimental modules and development releases of contributed modules.
+ *   See https://www.drupal.org/core/experimental for more information.
+ */
+class SectionStorageManager extends DefaultPluginManager implements SectionStorageManagerInterface {
+
+  /**
+   * Constructs a new SectionStorageManager object.
+   *
+   * @param \Traversable $namespaces
+   *   An object that implements \Traversable which contains the root paths
+   *   keyed by the corresponding namespace to look for plugin implementations.
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+   *   Cache backend instance to use.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler to invoke the alter hook with.
+   */
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Plugin/SectionStorage', $namespaces, $module_handler, SectionStorageInterface::class, SectionStorage::class);
+
+    $this->alterInfo('layout_builder_section_storage');
+    $this->setCacheBackend($cache_backend, 'layout_builder_section_storage_plugins');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function loadEmpty($id) {
+    return $this->createInstance($id);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function loadFromStorageId($type, $id) {
+    /** @var \Drupal\layout_builder\SectionStorageInterface $plugin */
+    $plugin = $this->createInstance($type);
+    return $plugin->setSectionList($plugin->getSectionListFromId($id));
+  }
+
+  /**
+   * {@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.
+      }
+    }
+  }
+
+}
diff --git a/core/modules/layout_builder/src/SectionStorage/SectionStorageManagerInterface.php b/core/modules/layout_builder/src/SectionStorage/SectionStorageManagerInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..3b269fcbba839240b4998401a7dcefc999c65434
--- /dev/null
+++ b/core/modules/layout_builder/src/SectionStorage/SectionStorageManagerInterface.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Drupal\layout_builder\SectionStorage;
+
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+
+/**
+ * Provides the interface for a plugin manager of section storage types.
+ *
+ * @internal
+ *   Layout Builder is currently experimental and should only be leveraged by
+ *   experimental modules and development releases of contributed modules.
+ *   See https://www.drupal.org/core/experimental for more information.
+ */
+interface SectionStorageManagerInterface extends DiscoveryInterface {
+
+  /**
+   * Loads a section storage with no associated section list.
+   *
+   * @param string $id
+   *   The ID of the section storage being instantiated.
+   *
+   * @return \Drupal\layout_builder\SectionStorageInterface
+   *   The section storage.
+   */
+  public function loadEmpty($id);
+
+  /**
+   * Loads a section storage populated with an existing section list.
+   *
+   * @param string $type
+   *   The section storage type.
+   * @param string $id
+   *   The section list ID.
+   *
+   * @return \Drupal\layout_builder\SectionStorageInterface
+   *   The section storage.
+   *
+   * @throws \InvalidArgumentException
+   *   Thrown if the ID is invalid.
+   */
+  public function loadFromStorageId($type, $id);
+
+  /**
+   * Loads a section storage populated with a section list derived from a route.
+   *
+   * @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.
+   *
+   * @return \Drupal\layout_builder\SectionStorageInterface|null
+   *   The section storage if it could be loaded, or NULL otherwise.
+   *
+   * @see \Drupal\Core\ParamConverter\ParamConverterInterface::convert()
+   */
+  public function loadFromRoute($type, $value, $definition, $name, array $defaults);
+
+}
diff --git a/core/modules/layout_builder/src/SectionStorage/SectionStorageTrait.php b/core/modules/layout_builder/src/SectionStorage/SectionStorageTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..9d942c7ad85982898e0480f3f7cac4d075b2f83e
--- /dev/null
+++ b/core/modules/layout_builder/src/SectionStorage/SectionStorageTrait.php
@@ -0,0 +1,114 @@
+<?php
+
+namespace Drupal\layout_builder\SectionStorage;
+
+use Drupal\layout_builder\Section;
+
+/**
+ * Provides a trait for storing sections on an object.
+ *
+ * @internal
+ *   Layout Builder is currently experimental and should only be leveraged by
+ *   experimental modules and development releases of contributed modules.
+ *   See https://www.drupal.org/core/experimental for more information.
+ */
+trait SectionStorageTrait {
+
+  /**
+   * Stores the information for all sections.
+   *
+   * Implementations of this method are expected to call array_values() to rekey
+   * the list of sections.
+   *
+   * @param \Drupal\layout_builder\Section[] $sections
+   *   An array of section objects.
+   *
+   * @return $this
+   */
+  abstract protected function setSections(array $sections);
+
+  /**
+   * {@inheritdoc}
+   */
+  public function count() {
+    return count($this->getSections());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSection($delta) {
+    if (!$this->hasSection($delta)) {
+      throw new \OutOfBoundsException(sprintf('Invalid delta "%s"', $delta));
+    }
+
+    return $this->getSections()[$delta];
+  }
+
+  /**
+   * Sets the section for the given delta on the display.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   * @param \Drupal\layout_builder\Section $section
+   *   The layout section.
+   *
+   * @return $this
+   */
+  protected function setSection($delta, Section $section) {
+    $sections = $this->getSections();
+    $sections[$delta] = $section;
+    $this->setSections($sections);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function appendSection(Section $section) {
+    $delta = $this->count();
+
+    $this->setSection($delta, $section);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function insertSection($delta, Section $section) {
+    if ($this->hasSection($delta)) {
+      // @todo Use https://www.drupal.org/node/66183 once resolved.
+      $start = array_slice($this->getSections(), 0, $delta);
+      $end = array_slice($this->getSections(), $delta);
+      $this->setSections(array_merge($start, [$section], $end));
+    }
+    else {
+      $this->appendSection($section);
+    }
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function removeSection($delta) {
+    $sections = $this->getSections();
+    unset($sections[$delta]);
+    $this->setSections($sections);
+    return $this;
+  }
+
+  /**
+   * Indicates if there is a section at the specified delta.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   *
+   * @return bool
+   *   TRUE if there is a section for this delta, FALSE otherwise.
+   */
+  protected function hasSection($delta) {
+    return isset($this->getSections()[$delta]);
+  }
+
+}
diff --git a/core/modules/layout_builder/src/SectionStorageInterface.php b/core/modules/layout_builder/src/SectionStorageInterface.php
index cc1efaba2a62586a318e804c7184f8e38095d5aa..e7fbb086b89da585cfde215c14e84d7ef468491c 100644
--- a/core/modules/layout_builder/src/SectionStorageInterface.php
+++ b/core/modules/layout_builder/src/SectionStorageInterface.php
@@ -2,100 +2,124 @@
 
 namespace Drupal\layout_builder;
 
+use Drupal\Component\Plugin\PluginInspectionInterface;
+use Symfony\Component\Routing\RouteCollection;
+
 /**
- * Defines the interface for an object that stores layout sections.
+ * Defines an interface for Section Storage type plugins.
  *
  * @internal
  *   Layout Builder is currently experimental and should only be leveraged by
  *   experimental modules and development releases of contributed modules.
  *   See https://www.drupal.org/core/experimental for more information.
- *
- * @see \Drupal\layout_builder\Section
  */
-interface SectionStorageInterface extends \Countable {
+interface SectionStorageInterface extends SectionListInterface, PluginInspectionInterface {
 
   /**
-   * Gets the layout sections.
+   * Returns an identifier for this storage.
    *
-   * @return \Drupal\layout_builder\Section[]
-   *   A sequentially and numerically keyed array of section objects.
+   * @return string
+   *   The unique identifier for this storage.
    */
-  public function getSections();
+  public function getStorageId();
 
   /**
-   * Gets a domain object for the layout section.
+   * Returns the type of this storage.
    *
-   * @param int $delta
-   *   The delta of the section.
+   * Used in conjunction with the storage ID.
    *
-   * @return \Drupal\layout_builder\Section
-   *   The layout section.
+   * @return string
+   *   The type of storage.
    */
-  public function getSection($delta);
+  public function getStorageType();
 
   /**
-   * Appends a new section to the end of the list.
+   * Sets the section list on the storage.
    *
-   * @param \Drupal\layout_builder\Section $section
-   *   The section to append.
+   * @param \Drupal\layout_builder\SectionListInterface $section_list
+   *   The section list.
    *
    * @return $this
+   *
+   * @internal
+   *   This should only be called during section storage instantiation.
    */
-  public function appendSection(Section $section);
+  public function setSectionList(SectionListInterface $section_list);
 
   /**
-   * Inserts a new section at a given delta.
+   * Derives the section list from the storage ID.
    *
-   * If a section exists at the given index, the section at that position and
-   * others after it are shifted backward.
+   * @param string $id
+   *   The storage ID, see ::getStorageId().
    *
-   * @param int $delta
-   *   The delta of the section.
-   * @param \Drupal\layout_builder\Section $section
-   *   The section to insert.
+   * @return \Drupal\layout_builder\SectionListInterface
+   *   The section list.
    *
-   * @return $this
+   * @throws \InvalidArgumentException
+   *   Thrown if the ID is invalid.
+   *
+   * @internal
+   *   This should only be called during section storage instantiation.
    */
-  public function insertSection($delta, Section $section);
+  public function getSectionListFromId($id);
 
   /**
-   * Removes the section at the given delta.
+   * Provides the routes needed for Layout Builder UI.
    *
-   * As sections are stored sequentially and numerically this will re-key every
-   * subsequent section, shifting them forward.
+   * Allows the plugin to add or alter routes during the route building process.
+   * \Drupal\layout_builder\Routing\LayoutBuilderRoutesTrait is provided for the
+   * typical use case of building a standard Layout Builder UI.
    *
-   * @param int $delta
-   *   The delta of the section.
+   * @param \Symfony\Component\Routing\RouteCollection $collection
+   *   The route collection.
    *
-   * @return $this
+   * @see \Drupal\Core\Routing\RoutingEvents::ALTER
    */
-  public function removeSection($delta);
+  public function buildRoutes(RouteCollection $collection);
 
   /**
-   * Provides any available contexts for the object using the sections.
+   * Gets the URL used when redirecting away from the Layout Builder UI.
    *
-   * @return \Drupal\Core\Plugin\Context\ContextInterface[]
-   *   The array of context objects.
+   * @return \Drupal\Core\Url
+   *   The URL object.
    */
-  public function getContexts();
+  public function getRedirectUrl();
 
   /**
-   * Returns an identifier for this storage.
+   * Gets the URL used to display the Layout Builder UI.
    *
-   * @return string
-   *   The unique identifier for this storage.
+   * @return \Drupal\Core\Url
+   *   The URL object.
    */
-  public function getStorageId();
+  public function getLayoutBuilderUrl();
 
   /**
-   * Returns the type of this storage.
-   *
-   * Used in conjunction with the storage ID.
+   * Configures the plugin based on route values.
+   *
+   * @param mixed $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.
+   *
+   * @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 string
-   *   The type of storage.
+   * @return \Drupal\Core\Plugin\Context\ContextInterface[]
+   *   The array of context objects.
    */
-  public static function getStorageType();
+  public function getContexts();
 
   /**
    * Gets the label for the object using the sections.
@@ -114,20 +138,4 @@ public function label();
    */
   public function save();
 
-  /**
-   * Returns a URL for viewing the object using the sections.
-   *
-   * @return \Drupal\Core\Url
-   *   The URL object.
-   */
-  public function getCanonicalUrl();
-
-  /**
-   * Returns a URL to edit the sections in the Layout Builder UI.
-   *
-   * @return \Drupal\Core\Url
-   *   The URL object.
-   */
-  public function getLayoutBuilderUrl();
-
 }
diff --git a/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php b/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php
index e0dfdc7f429d16b99c74b63994099715da2769d0..0437c1ca8538b198746a989ba22040d1763fde30 100644
--- a/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php
+++ b/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php
@@ -169,10 +169,11 @@ public function providerTestLayoutSectionFormatter() {
   public function testLayoutSectionFormatter($layout_data, $expected_selector, $expected_content, $expected_cache_contexts, $expected_cache_tags, $expected_dynamic_cache) {
     $node = $this->createSectionNode($layout_data);
 
-    $this->drupalGet($node->toUrl('canonical'));
+    $canonical_url = $node->toUrl('canonical');
+    $this->drupalGet($canonical_url);
     $this->assertLayoutSection($expected_selector, $expected_content, $expected_cache_contexts, $expected_cache_tags, $expected_dynamic_cache);
 
-    $this->drupalGet($node->toUrl('layout-builder'));
+    $this->drupalGet($canonical_url->toString() . '/layout');
     $this->assertLayoutSection($expected_selector, $expected_content, $expected_cache_contexts, $expected_cache_tags, 'UNCACHEABLE');
   }
 
@@ -255,7 +256,7 @@ public function testLayoutPageTitle() {
     $this->drupalPlaceBlock('page_title_block');
     $node = $this->createSectionNode([]);
 
-    $this->drupalGet($node->toUrl('layout-builder'));
+    $this->drupalGet($node->toUrl('canonical')->toString() . '/layout');
     $this->assertSession()->titleEquals('Edit layout for The node title | Drupal');
     $this->assertEquals('Edit layout for The node title', $this->cssSelect('h1.page-title')[0]->getText());
   }
@@ -274,7 +275,8 @@ public function testLayoutUrlNoSectionField() {
       ],
     ]);
     $node->save();
-    $this->drupalGet($node->toUrl('layout-builder'));
+
+    $this->drupalGet($node->toUrl('canonical')->toString() . '/layout');
     $this->assertSession()->statusCodeEquals(404);
   }
 
diff --git a/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php
index 034a76628e3cec5cb566cb212e15583745f257d0..a554fb526f93582976755b47438e1c5714bdeb7a 100644
--- a/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php
+++ b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php
@@ -31,14 +31,6 @@ protected function getSectionStorage(array $section_data) {
     return $display;
   }
 
-  /**
-   * @covers ::getSection
-   */
-  public function testGetSectionInvalidDelta() {
-    $this->setExpectedException(\OutOfBoundsException::class, 'Invalid delta "2" for the "entity_test.entity_test.default"');
-    $this->sectionStorage->getSection(2);
-  }
-
   /**
    * Tests that configuration schema enforces valid values.
    */
diff --git a/core/modules/layout_builder/tests/src/Kernel/SectionStorageTestBase.php b/core/modules/layout_builder/tests/src/Kernel/SectionStorageTestBase.php
index 151cf736f974f27e8d74fbc53f2434f76bc9e625..1879977633e3abc9b192d8fafc41c22f082c3311 100644
--- a/core/modules/layout_builder/tests/src/Kernel/SectionStorageTestBase.php
+++ b/core/modules/layout_builder/tests/src/Kernel/SectionStorageTestBase.php
@@ -83,7 +83,7 @@ public function testGetSection() {
    * @covers ::getSection
    */
   public function testGetSectionInvalidDelta() {
-    $this->setExpectedException(\OutOfBoundsException::class, 'Invalid delta "2" for the "The test entity"');
+    $this->setExpectedException(\OutOfBoundsException::class, 'Invalid delta "2"');
     $this->sectionStorage->getSection(2);
   }
 
diff --git a/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php b/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1aa1c16cf4ab8386274e50e9d50dfc80d242bcf7
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Unit/DefaultsSectionStorageTest.php
@@ -0,0 +1,339 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\Unit;
+
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Entity\EntityType;
+use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\layout_builder\Entity\LayoutBuilderSampleEntityGenerator;
+use Drupal\layout_builder\Plugin\SectionStorage\DefaultsSectionStorage;
+use Drupal\layout_builder\SectionStorage\SectionStorageDefinition;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * @coversDefaultClass \Drupal\layout_builder\Plugin\SectionStorage\DefaultsSectionStorage
+ *
+ * @group layout_builder
+ */
+class DefaultsSectionStorageTest extends UnitTestCase {
+
+  /**
+   * The plugin.
+   *
+   * @var \Drupal\layout_builder\Plugin\SectionStorage\DefaultsSectionStorage
+   */
+  protected $plugin;
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class);
+    $entity_type_bundle_info = $this->prophesize(EntityTypeBundleInfoInterface::class);
+    $sample_entity_generator = $this->prophesize(LayoutBuilderSampleEntityGenerator::class);
+
+    $definition = new SectionStorageDefinition([
+      'id' => 'defaults',
+      'class' => DefaultsSectionStorage::class,
+    ]);
+    $this->plugin = new DefaultsSectionStorage([], '', $definition, $this->entityTypeManager->reveal(), $entity_type_bundle_info->reveal(), $sample_entity_generator->reveal());
+  }
+
+  /**
+   * @covers ::extractIdFromRoute
+   *
+   * @dataProvider providerTestExtractIdFromRoute
+   */
+  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) {
+    if ($expected_entity_id) {
+      $entity_storage = $this->prophesize(EntityStorageInterface::class);
+      $entity_storage->load($expected_entity_id)->willReturn('the_return_value');
+
+      $this->entityTypeManager->getDefinition('entity_view_display')->willReturn(new EntityType(['id' => 'entity_view_display']));
+      $this->entityTypeManager->getStorage('entity_view_display')->willReturn($entity_storage->reveal());
+    }
+    else {
+      $this->entityTypeManager->getDefinition('entity_view_display')->shouldNotBeCalled();
+      $this->entityTypeManager->getStorage('entity_view_display')->shouldNotBeCalled();
+    }
+
+    if (!$success) {
+      $this->setExpectedException(\InvalidArgumentException::class);
+    }
+
+    $result = $this->plugin->getSectionListFromId($value);
+    if ($success) {
+      $this->assertEquals('the_return_value', $result);
+    }
+  }
+
+  /**
+   * Provides data for ::testGetSectionListFromId().
+   */
+  public function providerTestGetSectionListFromId() {
+    $data = [];
+    $data['with value'] = [
+      TRUE,
+      'foo.bar.baz',
+      'foo.bar.baz',
+    ];
+    $data['without value, empty defaults'] = [
+      FALSE,
+      NULL,
+      '',
+    ];
+    return $data;
+  }
+
+  /**
+   * @covers ::getSectionListFromId
+   */
+  public function testGetSectionListFromIdCreate() {
+    $expected = 'the_return_value';
+    $value = 'foo.bar.baz';
+    $expected_create_values = [
+      'targetEntityType' => 'foo',
+      'bundle' => 'bar',
+      'mode' => 'baz',
+      'status' => TRUE,
+    ];
+    $entity_storage = $this->prophesize(EntityStorageInterface::class);
+    $entity_storage->load($value)->willReturn(NULL);
+    $entity_storage->create($expected_create_values)->willReturn($expected);
+
+    $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);
+    $this->assertSame($expected, $result);
+  }
+
+  /**
+   * @covers ::buildRoutes
+   * @covers ::getEntityTypes
+   */
+  public function testBuildRoutes() {
+    $entity_types = [];
+    $entity_types['no_link_template'] = new EntityType(['id' => 'no_link_template']);
+    $entity_types['unknown_field_ui_route'] = new EntityType([
+      'id' => 'unknown_field_ui_route',
+      'links' => ['layout-builder' => '/entity/{entity}/layout'],
+      'entity_keys' => ['id' => 'id'],
+      'field_ui_base_route' => 'unknown',
+    ]);
+    $entity_types['with_bundle_key'] = new EntityType([
+      'id' => 'with_bundle_key',
+      'links' => ['layout-builder' => '/entity/{entity}/layout'],
+      'entity_keys' => ['id' => 'id', 'bundle' => 'bundle'],
+      'bundle_entity_type' => 'my_bundle_type',
+      'field_ui_base_route' => 'known',
+    ]);
+    $entity_types['with_bundle_parameter'] = new EntityType([
+      'id' => 'with_bundle_parameter',
+      'links' => ['layout-builder' => '/entity/{entity}/layout'],
+      'entity_keys' => ['id' => 'id'],
+      'field_ui_base_route' => 'with_bundle',
+    ]);
+    $this->entityTypeManager->getDefinitions()->willReturn($entity_types);
+
+    $expected = [
+      'known' => new Route('/admin/entity/whatever', [], [], ['_admin_route' => TRUE]),
+      'with_bundle' => new Route('/admin/entity/{bundle}'),
+      'layout_builder.defaults.with_bundle_key.view' => new Route(
+        '/admin/entity/whatever/display-layout/{view_mode_name}',
+        [
+          'entity_type_id' => 'with_bundle_key',
+          'bundle_key' => 'my_bundle_type',
+          'section_storage_type' => 'defaults',
+          'section_storage' => '',
+          'is_rebuilding' => FALSE,
+          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::layout',
+          '_title_callback' => '\Drupal\layout_builder\Controller\LayoutBuilderController::title',
+        ],
+        [
+          '_field_ui_view_mode_access' => 'administer with_bundle_key display',
+          '_has_layout_section' => 'true',
+        ],
+        [
+          'parameters' => [
+            'section_storage' => ['layout_builder_tempstore' => TRUE],
+          ],
+          '_layout_builder' => TRUE,
+          '_admin_route' => FALSE,
+        ]
+      ),
+      'layout_builder.defaults.with_bundle_key.save' => new Route(
+        '/admin/entity/whatever/display-layout/{view_mode_name}/save',
+        [
+          'entity_type_id' => 'with_bundle_key',
+          'bundle_key' => 'my_bundle_type',
+          'section_storage_type' => 'defaults',
+          'section_storage' => '',
+          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout',
+        ],
+        [
+          '_field_ui_view_mode_access' => 'administer with_bundle_key display',
+          '_has_layout_section' => 'true',
+        ],
+        [
+          'parameters' => [
+            'section_storage' => ['layout_builder_tempstore' => TRUE],
+          ],
+          '_layout_builder' => TRUE,
+          '_admin_route' => FALSE,
+        ]
+      ),
+      'layout_builder.defaults.with_bundle_key.cancel' => new Route(
+        '/admin/entity/whatever/display-layout/{view_mode_name}/cancel',
+        [
+          'entity_type_id' => 'with_bundle_key',
+          'bundle_key' => 'my_bundle_type',
+          'section_storage_type' => 'defaults',
+          'section_storage' => '',
+          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout',
+        ],
+        [
+          '_field_ui_view_mode_access' => 'administer with_bundle_key display',
+          '_has_layout_section' => 'true',
+        ],
+        [
+          'parameters' => [
+            'section_storage' => ['layout_builder_tempstore' => TRUE],
+          ],
+          '_layout_builder' => TRUE,
+          '_admin_route' => FALSE,
+        ]
+      ),
+      'layout_builder.defaults.with_bundle_parameter.view' => new Route(
+        '/admin/entity/{bundle}/display-layout/{view_mode_name}',
+        [
+          'entity_type_id' => 'with_bundle_parameter',
+          'section_storage_type' => 'defaults',
+          'section_storage' => '',
+          'is_rebuilding' => FALSE,
+          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::layout',
+          '_title_callback' => '\Drupal\layout_builder\Controller\LayoutBuilderController::title',
+        ],
+        [
+          '_field_ui_view_mode_access' => 'administer with_bundle_parameter display',
+          '_has_layout_section' => 'true',
+        ],
+        [
+          'parameters' => [
+            'section_storage' => ['layout_builder_tempstore' => TRUE],
+          ],
+          '_layout_builder' => TRUE,
+          '_admin_route' => FALSE,
+        ]
+      ),
+      'layout_builder.defaults.with_bundle_parameter.save' => new Route(
+        '/admin/entity/{bundle}/display-layout/{view_mode_name}/save',
+        [
+          'entity_type_id' => 'with_bundle_parameter',
+          'section_storage_type' => 'defaults',
+          'section_storage' => '',
+          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout',
+        ],
+        [
+          '_field_ui_view_mode_access' => 'administer with_bundle_parameter display',
+          '_has_layout_section' => 'true',
+        ],
+        [
+          'parameters' => [
+            'section_storage' => ['layout_builder_tempstore' => TRUE],
+          ],
+          '_layout_builder' => TRUE,
+          '_admin_route' => FALSE,
+        ]
+      ),
+      'layout_builder.defaults.with_bundle_parameter.cancel' => new Route(
+        '/admin/entity/{bundle}/display-layout/{view_mode_name}/cancel',
+        [
+          'entity_type_id' => 'with_bundle_parameter',
+          'section_storage_type' => 'defaults',
+          'section_storage' => '',
+          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout',
+        ],
+        [
+          '_field_ui_view_mode_access' => 'administer with_bundle_parameter display',
+          '_has_layout_section' => 'true',
+        ],
+        [
+          'parameters' => [
+            'section_storage' => ['layout_builder_tempstore' => TRUE],
+          ],
+          '_layout_builder' => TRUE,
+          '_admin_route' => FALSE,
+        ]
+      ),
+    ];
+
+    $collection = new RouteCollection();
+    $collection->add('known', new Route('/admin/entity/whatever', [], [], ['_admin_route' => TRUE]));
+    $collection->add('with_bundle', new Route('/admin/entity/{bundle}'));
+
+    $this->plugin->buildRoutes($collection);
+    $this->assertEquals($expected, $collection->all());
+    $this->assertSame(array_keys($expected), array_keys($collection->all()));
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Unit/LayoutBuilderRoutesTest.php b/core/modules/layout_builder/tests/src/Unit/LayoutBuilderRoutesTest.php
index 961b870429880582cbc30b44100550922ddc5e7f..e4b20bd840c9f37e778718c3c9c0cb9380b36a75 100644
--- a/core/modules/layout_builder/tests/src/Unit/LayoutBuilderRoutesTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/LayoutBuilderRoutesTest.php
@@ -2,13 +2,13 @@
 
 namespace Drupal\Tests\layout_builder\Unit;
 
-use Drupal\Core\Entity\EntityFieldManagerInterface;
-use Drupal\Core\Entity\EntityType;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Routing\RouteBuildEvent;
 use Drupal\layout_builder\Routing\LayoutBuilderRoutes;
+use Drupal\layout_builder\SectionStorage\SectionStorageDefinition;
+use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface;
+use Drupal\layout_builder\SectionStorageInterface;
 use Drupal\Tests\UnitTestCase;
+use Prophecy\Argument;
 use Symfony\Component\Routing\Route;
 use Symfony\Component\Routing\RouteCollection;
 
@@ -19,6 +19,13 @@
  */
 class LayoutBuilderRoutesTest extends UnitTestCase {
 
+  /**
+   * The Layout Builder route builder.
+   *
+   * @var \Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface
+   */
+  protected $sectionStorageManager;
+
   /**
    * The Layout Builder route builder.
    *
@@ -32,685 +39,46 @@ class LayoutBuilderRoutesTest extends UnitTestCase {
   protected function setUp() {
     parent::setUp();
 
-    $entity_types = [];
-    $entity_types['no_link_template'] = new EntityType(['id' => 'no_link_template']);
-    $entity_types['with_link_template'] = new EntityType([
-      'id' => 'with_link_template',
-      'links' => ['layout-builder' => '/entity/{entity}/layout'],
-      'entity_keys' => ['id' => 'id'],
-      'field_ui_base_route' => 'unknown',
-    ]);
-    $entity_types['with_integer_id'] = new EntityType([
-      'id' => 'with_integer_id',
-      'links' => ['layout-builder' => '/entity/{entity}/layout'],
-      'entity_keys' => ['id' => 'id'],
-    ]);
-    $entity_types['with_field_ui_route'] = new EntityType([
-      'id' => 'with_field_ui_route',
-      'links' => ['layout-builder' => '/entity/{entity}/layout'],
-      'entity_keys' => ['id' => 'id'],
-      'field_ui_base_route' => 'known',
-    ]);
-    $entity_types['with_bundle_key'] = new EntityType([
-      'id' => 'with_field_ui_route',
-      'links' => ['layout-builder' => '/entity/{entity}/layout'],
-      'entity_keys' => ['id' => 'id', 'bundle' => 'bundle'],
-      'bundle_entity_type' => 'my_bundle_type',
-      'field_ui_base_route' => 'known',
-    ]);
-    $entity_types['with_bundle_parameter'] = new EntityType([
-      'id' => 'with_bundle_parameter',
-      'links' => ['layout-builder' => '/entity/{entity}/layout'],
-      'entity_keys' => ['id' => 'id'],
-      'field_ui_base_route' => 'with_bundle',
-    ]);
-    $entity_type_manager = $this->prophesize(EntityTypeManagerInterface::class);
-    $entity_type_manager->getDefinitions()->willReturn($entity_types);
-
-    $string_id = $this->prophesize(FieldStorageDefinitionInterface::class);
-    $string_id->getType()->willReturn('string');
-    $integer_id = $this->prophesize(FieldStorageDefinitionInterface::class);
-    $integer_id->getType()->willReturn('integer');
-    $entity_field_manager = $this->prophesize(EntityFieldManagerInterface::class);
-    $entity_field_manager->getFieldStorageDefinitions('no_link_template')->shouldNotBeCalled();
-    $entity_field_manager->getFieldStorageDefinitions('with_link_template')->willReturn(['id' => $string_id->reveal()]);
-    $entity_field_manager->getFieldStorageDefinitions('with_integer_id')->willReturn(['id' => $integer_id->reveal()]);
-    $entity_field_manager->getFieldStorageDefinitions('with_field_ui_route')->willReturn(['id' => $integer_id->reveal()]);
-    $entity_field_manager->getFieldStorageDefinitions('with_bundle_parameter')->willReturn(['id' => $integer_id->reveal()]);
-
-    $this->routeBuilder = new LayoutBuilderRoutes($entity_type_manager->reveal(), $entity_field_manager->reveal());
+    $this->sectionStorageManager = $this->prophesize(SectionStorageManagerInterface::class);
+    $this->routeBuilder = new LayoutBuilderRoutes($this->sectionStorageManager->reveal());
   }
 
   /**
-   * @covers ::getRoutes
-   * @covers ::buildRoute
-   * @covers ::hasIntegerId
-   * @covers ::getEntityTypes
+   * @covers ::onAlterRoutes
    */
-  public function testGetRoutes() {
+  public function testOnAlterRoutes() {
     $expected = [
-      'entity.with_link_template.layout_builder' => new Route(
-        '/entity/{entity}/layout',
-        [
-          'entity_type_id' => 'with_link_template',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          'is_rebuilding' => FALSE,
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::layout',
-          '_title_callback' => '\Drupal\layout_builder\Controller\LayoutBuilderController::title',
-        ],
-        [
-          '_has_layout_section' => 'true',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_link_template' => ['type' => 'entity:with_link_template'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_link_template.layout_builder_save' => new Route(
-        '/entity/{entity}/layout/save',
-        [
-          'entity_type_id' => 'with_link_template',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout',
-        ],
-        [
-          '_has_layout_section' => 'true',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_link_template' => ['type' => 'entity:with_link_template'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_link_template.layout_builder_cancel' => new Route(
-        '/entity/{entity}/layout/cancel',
-        [
-          'entity_type_id' => 'with_link_template',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout',
-        ],
-        [
-          '_has_layout_section' => 'true',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_link_template' => ['type' => 'entity:with_link_template'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_link_template.layout_builder_revert' => new Route(
-        '/entity/{entity}/layout/revert',
-        [
-          'entity_type_id' => 'with_link_template',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_form' => '\Drupal\layout_builder\Form\RevertOverridesForm',
-        ],
-        [
-          '_has_layout_section' => 'true',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_link_template' => ['type' => 'entity:with_link_template'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_integer_id.layout_builder' => new Route(
-        '/entity/{entity}/layout',
-        [
-          'entity_type_id' => 'with_integer_id',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          'is_rebuilding' => FALSE,
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::layout',
-          '_title_callback' => '\Drupal\layout_builder\Controller\LayoutBuilderController::title',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_integer_id' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_integer_id' => ['type' => 'entity:with_integer_id'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_integer_id.layout_builder_save' => new Route(
-        '/entity/{entity}/layout/save',
-        [
-          'entity_type_id' => 'with_integer_id',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_integer_id' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_integer_id' => ['type' => 'entity:with_integer_id'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_integer_id.layout_builder_cancel' => new Route(
-        '/entity/{entity}/layout/cancel',
-        [
-          'entity_type_id' => 'with_integer_id',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_integer_id' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_integer_id' => ['type' => 'entity:with_integer_id'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_integer_id.layout_builder_revert' => new Route(
-        '/entity/{entity}/layout/revert',
-        [
-          'entity_type_id' => 'with_integer_id',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_form' => '\Drupal\layout_builder\Form\RevertOverridesForm',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_integer_id' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_integer_id' => ['type' => 'entity:with_integer_id'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_field_ui_route.layout_builder' => new Route(
-        '/entity/{entity}/layout',
-        [
-          'entity_type_id' => 'with_field_ui_route',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          'is_rebuilding' => FALSE,
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::layout',
-          '_title_callback' => '\Drupal\layout_builder\Controller\LayoutBuilderController::title',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_field_ui_route' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_field_ui_route' => ['type' => 'entity:with_field_ui_route'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_field_ui_route.layout_builder_save' => new Route(
-        '/entity/{entity}/layout/save',
-        [
-          'entity_type_id' => 'with_field_ui_route',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_field_ui_route' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_field_ui_route' => ['type' => 'entity:with_field_ui_route'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_field_ui_route.layout_builder_cancel' => new Route(
-        '/entity/{entity}/layout/cancel',
-        [
-          'entity_type_id' => 'with_field_ui_route',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_field_ui_route' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_field_ui_route' => ['type' => 'entity:with_field_ui_route'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_field_ui_route.layout_builder_revert' => new Route(
-        '/entity/{entity}/layout/revert',
-        [
-          'entity_type_id' => 'with_field_ui_route',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_form' => '\Drupal\layout_builder\Form\RevertOverridesForm',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_field_ui_route' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_field_ui_route' => ['type' => 'entity:with_field_ui_route'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_bundle_key.layout_builder' => new Route(
-        '/entity/{entity}/layout',
-        [
-          'entity_type_id' => 'with_bundle_key',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          'is_rebuilding' => FALSE,
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::layout',
-          '_title_callback' => '\Drupal\layout_builder\Controller\LayoutBuilderController::title',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_bundle_key' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_bundle_key' => ['type' => 'entity:with_bundle_key'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_bundle_key.layout_builder_save' => new Route(
-        '/entity/{entity}/layout/save',
-        [
-          'entity_type_id' => 'with_bundle_key',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_bundle_key' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_bundle_key' => ['type' => 'entity:with_bundle_key'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_bundle_key.layout_builder_cancel' => new Route(
-        '/entity/{entity}/layout/cancel',
-        [
-          'entity_type_id' => 'with_bundle_key',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_bundle_key' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_bundle_key' => ['type' => 'entity:with_bundle_key'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_bundle_key.layout_builder_revert' => new Route(
-        '/entity/{entity}/layout/revert',
-        [
-          'entity_type_id' => 'with_bundle_key',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_form' => '\Drupal\layout_builder\Form\RevertOverridesForm',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_bundle_key' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_bundle_key' => ['type' => 'entity:with_bundle_key'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_bundle_parameter.layout_builder' => new Route(
-        '/entity/{entity}/layout',
-        [
-          'entity_type_id' => 'with_bundle_parameter',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          'is_rebuilding' => FALSE,
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::layout',
-          '_title_callback' => '\Drupal\layout_builder\Controller\LayoutBuilderController::title',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_bundle_parameter' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_bundle_parameter' => ['type' => 'entity:with_bundle_parameter'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_bundle_parameter.layout_builder_save' => new Route(
-        '/entity/{entity}/layout/save',
-        [
-          'entity_type_id' => 'with_bundle_parameter',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_bundle_parameter' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_bundle_parameter' => ['type' => 'entity:with_bundle_parameter'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_bundle_parameter.layout_builder_cancel' => new Route(
-        '/entity/{entity}/layout/cancel',
-        [
-          'entity_type_id' => 'with_bundle_parameter',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_bundle_parameter' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_bundle_parameter' => ['type' => 'entity:with_bundle_parameter'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
-      'entity.with_bundle_parameter.layout_builder_revert' => new Route(
-        '/entity/{entity}/layout/revert',
-        [
-          'entity_type_id' => 'with_bundle_parameter',
-          'section_storage_type' => 'overrides',
-          'section_storage' => '',
-          '_form' => '\Drupal\layout_builder\Form\RevertOverridesForm',
-        ],
-        [
-          '_has_layout_section' => 'true',
-          'with_bundle_parameter' => '\d+',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-            'with_bundle_parameter' => ['type' => 'entity:with_bundle_parameter'],
-          ],
-          '_layout_builder' => TRUE,
-        ]
-      ),
+      'test_route1' => new Route('/test/path1'),
+      'test_route_shared' => new Route('/test/path/shared2'),
+      'test_route2' => new Route('/test/path2'),
     ];
 
-    $this->assertEquals($expected, $this->routeBuilder->getRoutes());
-  }
+    $section_storage_first = $this->prophesize(SectionStorageInterface::class);
+    $section_storage_first->buildRoutes(Argument::type(RouteCollection::class))->shouldBeCalled()->will(function ($args) {
+      /** @var \Symfony\Component\Routing\RouteCollection $collection */
+      $collection = $args[0];
+      $collection->add('test_route_shared', new Route('/test/path/shared1'));
+      $collection->add('test_route1', new Route('/test/path1'));
+    });
+    $section_storage_second = $this->prophesize(SectionStorageInterface::class);
+    $section_storage_second->buildRoutes(Argument::type(RouteCollection::class))->shouldBeCalled()->will(function ($args) {
+      /** @var \Symfony\Component\Routing\RouteCollection $collection */
+      $collection = $args[0];
+      $collection->add('test_route_shared', new Route('/test/path/shared2'));
+      $collection->add('test_route2', new Route('/test/path2'));
+    });
+
+    $this->sectionStorageManager->loadEmpty('first')->willReturn($section_storage_first->reveal());
+    $this->sectionStorageManager->loadEmpty('second')->willReturn($section_storage_second->reveal());
+    $definitions['first'] = new SectionStorageDefinition();
+    $definitions['second'] = new SectionStorageDefinition();
+    $this->sectionStorageManager->getDefinitions()->willReturn($definitions);
 
-  /**
-   * @covers ::onAlterRoutes
-   * @covers ::buildRoute
-   * @covers ::hasIntegerId
-   * @covers ::getEntityTypes
-   */
-  public function testOnAlterRoutes() {
     $collection = new RouteCollection();
-    $collection->add('known', new Route('/admin/entity/whatever', [], [], ['_admin_route' => TRUE]));
-    $collection->add('with_bundle', new Route('/admin/entity/{bundle}'));
     $event = new RouteBuildEvent($collection);
-
-    $expected = [
-      'known' => new Route('/admin/entity/whatever', [], [], ['_admin_route' => TRUE]),
-      'with_bundle' => new Route('/admin/entity/{bundle}'),
-      'entity.entity_view_display.with_field_ui_route.layout_builder' => new Route(
-        '/admin/entity/whatever/display-layout/{view_mode_name}',
-        [
-          'entity_type_id' => 'with_field_ui_route',
-          'bundle' => 'with_field_ui_route',
-          'section_storage_type' => 'defaults',
-          'section_storage' => '',
-          'is_rebuilding' => FALSE,
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::layout',
-          '_title_callback' => '\Drupal\layout_builder\Controller\LayoutBuilderController::title',
-        ],
-        [
-          '_field_ui_view_mode_access' => 'administer with_field_ui_route display',
-          '_has_layout_section' => 'true',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-          ],
-          '_layout_builder' => TRUE,
-          '_admin_route' => FALSE,
-        ]
-      ),
-      'entity.entity_view_display.with_field_ui_route.layout_builder_save' => new Route(
-        '/admin/entity/whatever/display-layout/{view_mode_name}/save',
-        [
-          'entity_type_id' => 'with_field_ui_route',
-          'bundle' => 'with_field_ui_route',
-          'section_storage_type' => 'defaults',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout',
-        ],
-        [
-          '_field_ui_view_mode_access' => 'administer with_field_ui_route display',
-          '_has_layout_section' => 'true',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-          ],
-          '_layout_builder' => TRUE,
-          '_admin_route' => FALSE,
-        ]
-      ),
-      'entity.entity_view_display.with_field_ui_route.layout_builder_cancel' => new Route(
-        '/admin/entity/whatever/display-layout/{view_mode_name}/cancel',
-        [
-          'entity_type_id' => 'with_field_ui_route',
-          'bundle' => 'with_field_ui_route',
-          'section_storage_type' => 'defaults',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout',
-        ],
-        [
-          '_field_ui_view_mode_access' => 'administer with_field_ui_route display',
-          '_has_layout_section' => 'true',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-          ],
-          '_layout_builder' => TRUE,
-          '_admin_route' => FALSE,
-        ]
-      ),
-      'entity.entity_view_display.with_bundle_key.layout_builder' => new Route(
-        '/admin/entity/whatever/display-layout/{view_mode_name}',
-        [
-          'entity_type_id' => 'with_bundle_key',
-          'bundle_key' => 'my_bundle_type',
-          'section_storage_type' => 'defaults',
-          'section_storage' => '',
-          'is_rebuilding' => FALSE,
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::layout',
-          '_title_callback' => '\Drupal\layout_builder\Controller\LayoutBuilderController::title',
-        ],
-        [
-          '_field_ui_view_mode_access' => 'administer with_bundle_key display',
-          '_has_layout_section' => 'true',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-          ],
-          '_layout_builder' => TRUE,
-          '_admin_route' => FALSE,
-        ]
-      ),
-      'entity.entity_view_display.with_bundle_key.layout_builder_save' => new Route(
-        '/admin/entity/whatever/display-layout/{view_mode_name}/save',
-        [
-          'entity_type_id' => 'with_bundle_key',
-          'bundle_key' => 'my_bundle_type',
-          'section_storage_type' => 'defaults',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout',
-        ],
-        [
-          '_field_ui_view_mode_access' => 'administer with_bundle_key display',
-          '_has_layout_section' => 'true',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-          ],
-          '_layout_builder' => TRUE,
-          '_admin_route' => FALSE,
-        ]
-      ),
-      'entity.entity_view_display.with_bundle_key.layout_builder_cancel' => new Route(
-        '/admin/entity/whatever/display-layout/{view_mode_name}/cancel',
-        [
-          'entity_type_id' => 'with_bundle_key',
-          'bundle_key' => 'my_bundle_type',
-          'section_storage_type' => 'defaults',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout',
-        ],
-        [
-          '_field_ui_view_mode_access' => 'administer with_bundle_key display',
-          '_has_layout_section' => 'true',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-          ],
-          '_layout_builder' => TRUE,
-          '_admin_route' => FALSE,
-        ]
-      ),
-      'entity.entity_view_display.with_bundle_parameter.layout_builder' => new Route(
-        '/admin/entity/{bundle}/display-layout/{view_mode_name}',
-        [
-          'entity_type_id' => 'with_bundle_parameter',
-          'section_storage_type' => 'defaults',
-          'section_storage' => '',
-          'is_rebuilding' => FALSE,
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::layout',
-          '_title_callback' => '\Drupal\layout_builder\Controller\LayoutBuilderController::title',
-        ],
-        [
-          '_field_ui_view_mode_access' => 'administer with_bundle_parameter display',
-          '_has_layout_section' => 'true',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-          ],
-          '_layout_builder' => TRUE,
-          '_admin_route' => FALSE,
-        ]
-      ),
-      'entity.entity_view_display.with_bundle_parameter.layout_builder_save' => new Route(
-        '/admin/entity/{bundle}/display-layout/{view_mode_name}/save',
-        [
-          'entity_type_id' => 'with_bundle_parameter',
-          'section_storage_type' => 'defaults',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout',
-        ],
-        [
-          '_field_ui_view_mode_access' => 'administer with_bundle_parameter display',
-          '_has_layout_section' => 'true',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-          ],
-          '_layout_builder' => TRUE,
-          '_admin_route' => FALSE,
-        ]
-      ),
-      'entity.entity_view_display.with_bundle_parameter.layout_builder_cancel' => new Route(
-        '/admin/entity/{bundle}/display-layout/{view_mode_name}/cancel',
-        [
-          'entity_type_id' => 'with_bundle_parameter',
-          'section_storage_type' => 'defaults',
-          'section_storage' => '',
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout',
-        ],
-        [
-          '_field_ui_view_mode_access' => 'administer with_bundle_parameter display',
-          '_has_layout_section' => 'true',
-        ],
-        [
-          'parameters' => [
-            'section_storage' => ['layout_builder_tempstore' => TRUE],
-          ],
-          '_layout_builder' => TRUE,
-          '_admin_route' => FALSE,
-        ]
-      ),
-    ];
-
     $this->routeBuilder->onAlterRoutes($event);
-    $this->assertEquals($expected, $event->getRouteCollection()->all());
+    $this->assertEquals($expected, $collection->all());
+    $this->assertSame(array_keys($expected), array_keys($collection->all()));
   }
 
 }
diff --git a/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreParamConverterTest.php b/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreParamConverterTest.php
index 3c3c9f40653a6348590b6d0aa7a00670fe6b5eb8..5f8dc051e3765e978ea7a8ed39fa7d95f41c4935 100644
--- a/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreParamConverterTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreParamConverterTest.php
@@ -2,10 +2,9 @@
 
 namespace Drupal\Tests\layout_builder\Unit;
 
-use Drupal\Core\DependencyInjection\ClassResolverInterface;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Drupal\layout_builder\Routing\LayoutTempstoreParamConverter;
-use Drupal\layout_builder\Routing\SectionStorageParamConverterInterface;
+use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface;
 use Drupal\layout_builder\SectionStorageInterface;
 use Drupal\Tests\UnitTestCase;
 
@@ -18,23 +17,23 @@ class LayoutTempstoreParamConverterTest extends UnitTestCase {
 
   /**
    * @covers ::convert
-   * @covers ::getParamConverterFromDefaults
    */
   public function testConvert() {
     $layout_tempstore_repository = $this->prophesize(LayoutTempstoreRepositoryInterface::class);
-    $class_resolver = $this->prophesize(ClassResolverInterface::class);
-    $param_converter = $this->prophesize(SectionStorageParamConverterInterface::class);
-    $converter = new LayoutTempstoreParamConverter($layout_tempstore_repository->reveal(), $class_resolver->reveal());
+    $section_storage_manager = $this->prophesize(SectionStorageManagerInterface::class);
+    $converter = new LayoutTempstoreParamConverter($layout_tempstore_repository->reveal(), $section_storage_manager->reveal());
+
+    $section_storage = $this->prophesize(SectionStorageInterface::class);
 
     $value = 'some_value';
     $definition = ['layout_builder_tempstore' => TRUE];
     $name = 'the_parameter_name';
     $defaults = ['section_storage_type' => 'my_type'];
-    $section_storage = $this->prophesize(SectionStorageInterface::class);
     $expected = 'the_return_value';
 
-    $class_resolver->getInstanceFromDefinition('layout_builder.section_storage_param_converter.my_type')->willReturn($param_converter->reveal());
-    $param_converter->convert($value, $definition, $name, $defaults)->willReturn($section_storage->reveal());
+    $section_storage_manager->hasDefinition('my_type')->willReturn(TRUE);
+    $section_storage_manager->loadFromRoute('my_type', $value, $definition, $name, $defaults)->willReturn($section_storage);
+
     $layout_tempstore_repository->get($section_storage->reveal())->willReturn($expected);
 
     $result = $converter->convert($value, $definition, $name, $defaults);
@@ -43,19 +42,19 @@ public function testConvert() {
 
   /**
    * @covers ::convert
-   * @covers ::getParamConverterFromDefaults
    */
   public function testConvertNoType() {
     $layout_tempstore_repository = $this->prophesize(LayoutTempstoreRepositoryInterface::class);
-    $class_resolver = $this->prophesize(ClassResolverInterface::class);
-    $converter = new LayoutTempstoreParamConverter($layout_tempstore_repository->reveal(), $class_resolver->reveal());
+    $section_storage_manager = $this->prophesize(SectionStorageManagerInterface::class);
+    $converter = new LayoutTempstoreParamConverter($layout_tempstore_repository->reveal(), $section_storage_manager->reveal());
 
     $value = 'some_value';
     $definition = ['layout_builder_tempstore' => TRUE];
     $name = 'the_parameter_name';
     $defaults = ['section_storage_type' => NULL];
 
-    $class_resolver->getInstanceFromDefinition()->shouldNotBeCalled();
+    $section_storage_manager->hasDefinition()->shouldNotBeCalled();
+    $section_storage_manager->loadFromRoute()->shouldNotBeCalled();
     $layout_tempstore_repository->get()->shouldNotBeCalled();
 
     $result = $converter->convert($value, $definition, $name, $defaults);
@@ -64,19 +63,19 @@ public function testConvertNoType() {
 
   /**
    * @covers ::convert
-   * @covers ::getParamConverterFromDefaults
    */
   public function testConvertInvalidConverter() {
     $layout_tempstore_repository = $this->prophesize(LayoutTempstoreRepositoryInterface::class);
-    $class_resolver = $this->prophesize(ClassResolverInterface::class);
-    $converter = new LayoutTempstoreParamConverter($layout_tempstore_repository->reveal(), $class_resolver->reveal());
+    $section_storage_manager = $this->prophesize(SectionStorageManagerInterface::class);
+    $converter = new LayoutTempstoreParamConverter($layout_tempstore_repository->reveal(), $section_storage_manager->reveal());
 
     $value = 'some_value';
     $definition = ['layout_builder_tempstore' => TRUE];
     $name = 'the_parameter_name';
     $defaults = ['section_storage_type' => 'invalid'];
 
-    $class_resolver->getInstanceFromDefinition('layout_builder.section_storage_param_converter.invalid')->willThrow(\InvalidArgumentException::class);
+    $section_storage_manager->hasDefinition('invalid')->willReturn(FALSE);
+    $section_storage_manager->loadFromRoute()->shouldNotBeCalled();
     $layout_tempstore_repository->get()->shouldNotBeCalled();
 
     $result = $converter->convert($value, $definition, $name, $defaults);
diff --git a/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreRepositoryTest.php b/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreRepositoryTest.php
index 5d1f691271d5b3280cdbe868089df9b51e2a6f25..0c74d01763290cc9d33daeda8ea5b2f8d4fc2894 100644
--- a/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreRepositoryTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreRepositoryTest.php
@@ -2,12 +2,11 @@
 
 namespace Drupal\Tests\layout_builder\Unit;
 
+use Drupal\Core\TempStore\SharedTempStore;
+use Drupal\Core\TempStore\SharedTempStoreFactory;
 use Drupal\layout_builder\LayoutTempstoreRepository;
-use Drupal\layout_builder\Section;
 use Drupal\layout_builder\SectionStorageInterface;
 use Drupal\Tests\UnitTestCase;
-use Drupal\Core\TempStore\SharedTempStore;
-use Drupal\Core\TempStore\SharedTempStoreFactory;
 
 /**
  * @coversDefaultClass \Drupal\layout_builder\LayoutTempstoreRepository
@@ -19,7 +18,9 @@ class LayoutTempstoreRepositoryTest extends UnitTestCase {
    * @covers ::get
    */
   public function testGetEmptyTempstore() {
-    $section_storage = new TestSectionStorage();
+    $section_storage = $this->prophesize(SectionStorageInterface::class);
+    $section_storage->getStorageType()->willReturn('my_storage_type');
+    $section_storage->getStorageId()->willReturn('my_storage_id');
 
     $tempstore = $this->prophesize(SharedTempStore::class);
     $tempstore->get('my_storage_id')->shouldBeCalled();
@@ -29,34 +30,38 @@ public function testGetEmptyTempstore() {
 
     $repository = new LayoutTempstoreRepository($tempstore_factory->reveal());
 
-    $result = $repository->get($section_storage);
-    $this->assertSame($section_storage, $result);
+    $result = $repository->get($section_storage->reveal());
+    $this->assertSame($section_storage->reveal(), $result);
   }
 
   /**
    * @covers ::get
    */
   public function testGetLoadedTempstore() {
-    $section_storage = new TestSectionStorage();
+    $section_storage = $this->prophesize(SectionStorageInterface::class);
+    $section_storage->getStorageType()->willReturn('my_storage_type');
+    $section_storage->getStorageId()->willReturn('my_storage_id');
 
-    $tempstore_section_storage = new TestSectionStorage();
+    $tempstore_section_storage = $this->prophesize(SectionStorageInterface::class);
     $tempstore = $this->prophesize(SharedTempStore::class);
-    $tempstore->get('my_storage_id')->willReturn(['section_storage' => $tempstore_section_storage]);
+    $tempstore->get('my_storage_id')->willReturn(['section_storage' => $tempstore_section_storage->reveal()]);
     $tempstore_factory = $this->prophesize(SharedTempStoreFactory::class);
     $tempstore_factory->get('layout_builder.section_storage.my_storage_type')->willReturn($tempstore->reveal());
 
     $repository = new LayoutTempstoreRepository($tempstore_factory->reveal());
 
-    $result = $repository->get($section_storage);
-    $this->assertSame($tempstore_section_storage, $result);
-    $this->assertNotSame($section_storage, $result);
+    $result = $repository->get($section_storage->reveal());
+    $this->assertSame($tempstore_section_storage->reveal(), $result);
+    $this->assertNotSame($section_storage->reveal(), $result);
   }
 
   /**
    * @covers ::get
    */
   public function testGetInvalidEntry() {
-    $section_storage = new TestSectionStorage();
+    $section_storage = $this->prophesize(SectionStorageInterface::class);
+    $section_storage->getStorageType()->willReturn('my_storage_type');
+    $section_storage->getStorageId()->willReturn('my_storage_id');
 
     $tempstore = $this->prophesize(SharedTempStore::class);
     $tempstore->get('my_storage_id')->willReturn(['section_storage' => 'this_is_not_an_entity']);
@@ -67,85 +72,7 @@ public function testGetInvalidEntry() {
     $repository = new LayoutTempstoreRepository($tempstore_factory->reveal());
 
     $this->setExpectedException(\UnexpectedValueException::class, 'The entry with storage type "my_storage_type" and ID "my_storage_id" is invalid');
-    $repository->get($section_storage);
-  }
-
-}
-
-/**
- * Provides a test implementation of section storage.
- *
- * @todo This works around https://github.com/phpspec/prophecy/issues/119.
- */
-class TestSectionStorage implements SectionStorageInterface {
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function getStorageType() {
-    return 'my_storage_type';
+    $repository->get($section_storage->reveal());
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  public function getStorageId() {
-    return 'my_storage_id';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function count() {}
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getSections() {}
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getSection($delta) {}
-
-  /**
-   * {@inheritdoc}
-   */
-  public function appendSection(Section $section) {}
-
-  /**
-   * {@inheritdoc}
-   */
-  public function insertSection($delta, Section $section) {}
-
-  /**
-   * {@inheritdoc}
-   */
-  public function removeSection($delta) {}
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getContexts() {}
-
-  /**
-   * {@inheritdoc}
-   */
-  public function label() {}
-
-  /**
-   * {@inheritdoc}
-   */
-  public function save() {}
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCanonicalUrl() {}
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getLayoutBuilderUrl() {}
-
 }
diff --git a/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php b/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..711ce5d40b477726311ee71f42c3928a205bcf52
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Unit/OverridesSectionStorageTest.php
@@ -0,0 +1,363 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\Unit;
+
+use Drupal\Core\Entity\EntityFieldManagerInterface;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Entity\EntityType;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\FieldableEntityInterface;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage;
+use Drupal\layout_builder\SectionStorage\SectionStorageDefinition;
+use Drupal\Tests\UnitTestCase;
+use Prophecy\Argument;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * @coversDefaultClass \Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage
+ *
+ * @group layout_builder
+ */
+class OverridesSectionStorageTest extends UnitTestCase {
+
+  /**
+   * The plugin.
+   *
+   * @var \Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage
+   */
+  protected $plugin;
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * The entity field manager.
+   *
+   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
+   */
+  protected $entityFieldManager;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class);
+    $this->entityFieldManager = $this->prophesize(EntityFieldManagerInterface::class);
+
+    $definition = new SectionStorageDefinition([
+      'id' => 'overrides',
+      'class' => OverridesSectionStorage::class,
+    ]);
+    $this->plugin = new OverridesSectionStorage([], 'overrides', $definition, $this->entityTypeManager->reveal(), $this->entityFieldManager->reveal());
+  }
+
+  /**
+   * @covers ::extractIdFromRoute
+   *
+   * @dataProvider providerTestExtractIdFromRoute
+   */
+  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;
+
+    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);
+    if ($success) {
+      $this->assertEquals('the_return_value', $result);
+    }
+  }
+
+  /**
+   * Provides data for ::testGetSectionListFromId().
+   */
+  public function providerTestGetSectionListFromId() {
+    $data = [];
+    $data['with value, with layout'] = [
+      TRUE,
+      'my_entity_type',
+      'my_entity_type.entity_with_layout',
+    ];
+    $data['with value, without layout'] = [
+      FALSE,
+      'my_entity_type',
+      'my_entity_type.entity_without_layout',
+    ];
+    $data['empty value, empty defaults'] = [
+      FALSE,
+      NULL,
+      '',
+    ];
+    return $data;
+  }
+
+  /**
+   * @covers ::buildRoutes
+   * @covers ::hasIntegerId
+   * @covers ::getEntityTypes
+   */
+  public function testBuildRoutes() {
+    $entity_types = [];
+
+    $entity_types['no_link_template'] = new EntityType(['id' => 'no_link_template']);
+    $this->entityFieldManager->getFieldStorageDefinitions('no_link_template')->shouldNotBeCalled();
+
+    $entity_types['with_string_id'] = new EntityType([
+      'id' => 'with_string_id',
+      'links' => ['layout-builder' => '/entity/{entity}/layout'],
+      'entity_keys' => ['id' => 'id'],
+    ]);
+    $string_id = $this->prophesize(FieldStorageDefinitionInterface::class);
+    $string_id->getType()->willReturn('string');
+    $this->entityFieldManager->getFieldStorageDefinitions('with_string_id')->willReturn(['id' => $string_id->reveal()]);
+
+    $entity_types['with_integer_id'] = new EntityType([
+      'id' => 'with_integer_id',
+      'links' => ['layout-builder' => '/entity/{entity}/layout'],
+      'entity_keys' => ['id' => 'id'],
+    ]);
+    $integer_id = $this->prophesize(FieldStorageDefinitionInterface::class);
+    $integer_id->getType()->willReturn('integer');
+    $this->entityFieldManager->getFieldStorageDefinitions('with_integer_id')->willReturn(['id' => $integer_id->reveal()]);
+
+    $this->entityTypeManager->getDefinitions()->willReturn($entity_types);
+
+    $expected = [
+      'layout_builder.overrides.with_string_id.view' => new Route(
+        '/entity/{entity}/layout',
+        [
+          'entity_type_id' => 'with_string_id',
+          'section_storage_type' => 'overrides',
+          'section_storage' => '',
+          'is_rebuilding' => FALSE,
+          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::layout',
+          '_title_callback' => '\Drupal\layout_builder\Controller\LayoutBuilderController::title',
+        ],
+        [
+          '_has_layout_section' => 'true',
+        ],
+        [
+          'parameters' => [
+            'section_storage' => ['layout_builder_tempstore' => TRUE],
+            'with_string_id' => ['type' => 'entity:with_string_id'],
+          ],
+          '_layout_builder' => TRUE,
+        ]
+      ),
+      'layout_builder.overrides.with_string_id.save' => new Route(
+        '/entity/{entity}/layout/save',
+        [
+          'entity_type_id' => 'with_string_id',
+          'section_storage_type' => 'overrides',
+          'section_storage' => '',
+          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout',
+        ],
+        [
+          '_has_layout_section' => 'true',
+        ],
+        [
+          'parameters' => [
+            'section_storage' => ['layout_builder_tempstore' => TRUE],
+            'with_string_id' => ['type' => 'entity:with_string_id'],
+          ],
+          '_layout_builder' => TRUE,
+        ]
+      ),
+      'layout_builder.overrides.with_string_id.cancel' => new Route(
+        '/entity/{entity}/layout/cancel',
+        [
+          'entity_type_id' => 'with_string_id',
+          'section_storage_type' => 'overrides',
+          'section_storage' => '',
+          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout',
+        ],
+        [
+          '_has_layout_section' => 'true',
+        ],
+        [
+          'parameters' => [
+            'section_storage' => ['layout_builder_tempstore' => TRUE],
+            'with_string_id' => ['type' => 'entity:with_string_id'],
+          ],
+          '_layout_builder' => TRUE,
+        ]
+      ),
+      'layout_builder.overrides.with_string_id.revert' => new Route(
+        '/entity/{entity}/layout/revert',
+        [
+          'entity_type_id' => 'with_string_id',
+          'section_storage_type' => 'overrides',
+          'section_storage' => '',
+          '_form' => '\Drupal\layout_builder\Form\RevertOverridesForm',
+        ],
+        [
+          '_has_layout_section' => 'true',
+        ],
+        [
+          'parameters' => [
+            'section_storage' => ['layout_builder_tempstore' => TRUE],
+            'with_string_id' => ['type' => 'entity:with_string_id'],
+          ],
+          '_layout_builder' => TRUE,
+        ]
+      ),
+      'layout_builder.overrides.with_integer_id.view' => new Route(
+        '/entity/{entity}/layout',
+        [
+          'entity_type_id' => 'with_integer_id',
+          'section_storage_type' => 'overrides',
+          'section_storage' => '',
+          'is_rebuilding' => FALSE,
+          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::layout',
+          '_title_callback' => '\Drupal\layout_builder\Controller\LayoutBuilderController::title',
+        ],
+        [
+          '_has_layout_section' => 'true',
+          'with_integer_id' => '\d+',
+        ],
+        [
+          'parameters' => [
+            'section_storage' => ['layout_builder_tempstore' => TRUE],
+            'with_integer_id' => ['type' => 'entity:with_integer_id'],
+          ],
+          '_layout_builder' => TRUE,
+        ]
+      ),
+      'layout_builder.overrides.with_integer_id.save' => new Route(
+        '/entity/{entity}/layout/save',
+        [
+          'entity_type_id' => 'with_integer_id',
+          'section_storage_type' => 'overrides',
+          'section_storage' => '',
+          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout',
+        ],
+        [
+          '_has_layout_section' => 'true',
+          'with_integer_id' => '\d+',
+        ],
+        [
+          'parameters' => [
+            'section_storage' => ['layout_builder_tempstore' => TRUE],
+            'with_integer_id' => ['type' => 'entity:with_integer_id'],
+          ],
+          '_layout_builder' => TRUE,
+        ]
+      ),
+      'layout_builder.overrides.with_integer_id.cancel' => new Route(
+        '/entity/{entity}/layout/cancel',
+        [
+          'entity_type_id' => 'with_integer_id',
+          'section_storage_type' => 'overrides',
+          'section_storage' => '',
+          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout',
+        ],
+        [
+          '_has_layout_section' => 'true',
+          'with_integer_id' => '\d+',
+        ],
+        [
+          'parameters' => [
+            'section_storage' => ['layout_builder_tempstore' => TRUE],
+            'with_integer_id' => ['type' => 'entity:with_integer_id'],
+          ],
+          '_layout_builder' => TRUE,
+        ]
+      ),
+      'layout_builder.overrides.with_integer_id.revert' => new Route(
+        '/entity/{entity}/layout/revert',
+        [
+          'entity_type_id' => 'with_integer_id',
+          'section_storage_type' => 'overrides',
+          'section_storage' => '',
+          '_form' => '\Drupal\layout_builder\Form\RevertOverridesForm',
+        ],
+        [
+          '_has_layout_section' => 'true',
+          'with_integer_id' => '\d+',
+        ],
+        [
+          'parameters' => [
+            'section_storage' => ['layout_builder_tempstore' => TRUE],
+            'with_integer_id' => ['type' => 'entity:with_integer_id'],
+          ],
+          '_layout_builder' => TRUE,
+        ]
+      ),
+    ];
+
+    $collection = new RouteCollection();
+    $this->plugin->buildRoutes($collection);
+    $this->assertEquals($expected, $collection->all());
+    $this->assertSame(array_keys($expected), array_keys($collection->all()));
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Unit/SectionStorageDefaultsParamConverterTest.php b/core/modules/layout_builder/tests/src/Unit/SectionStorageDefaultsParamConverterTest.php
deleted file mode 100644
index 8afde9a05558e91c18e0d3be5976666b30d97181..0000000000000000000000000000000000000000
--- a/core/modules/layout_builder/tests/src/Unit/SectionStorageDefaultsParamConverterTest.php
+++ /dev/null
@@ -1,134 +0,0 @@
-<?php
-
-namespace Drupal\Tests\layout_builder\Unit;
-
-use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\Core\Entity\EntityType;
-use Drupal\layout_builder\Routing\SectionStorageDefaultsParamConverter;
-use Drupal\Tests\UnitTestCase;
-
-/**
- * @coversDefaultClass \Drupal\layout_builder\Routing\SectionStorageDefaultsParamConverter
- *
- * @group layout_builder
- */
-class SectionStorageDefaultsParamConverterTest extends UnitTestCase {
-
-  /**
-   * The converter.
-   *
-   * @var \Drupal\layout_builder\Routing\SectionStorageDefaultsParamConverter
-   */
-  protected $converter;
-
-  /**
-   * The entity manager.
-   *
-   * @var \Drupal\Core\Entity\EntityManagerInterface
-   */
-  protected $entityManager;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    $this->entityManager = $this->prophesize(EntityManagerInterface::class);
-    $this->converter = new SectionStorageDefaultsParamConverter($this->entityManager->reveal());
-  }
-
-  /**
-   * @covers ::convert
-   * @covers ::getEntityTypeFromDefaults
-   *
-   * @dataProvider providerTestConvert
-   */
-  public function testConvert($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');
-
-      $this->entityManager->getDefinition('entity_view_display')->willReturn(new EntityType(['id' => 'entity_view_display']));
-      $this->entityManager->getStorage('entity_view_display')->willReturn($entity_storage->reveal());
-    }
-    else {
-      $this->entityManager->getDefinition('entity_view_display')->shouldNotBeCalled();
-      $this->entityManager->getStorage('entity_view_display')->shouldNotBeCalled();
-    }
-
-    $result = $this->converter->convert($value, [], 'the_parameter_name', $defaults);
-    if ($success) {
-      $this->assertEquals('the_return_value', $result);
-    }
-    else {
-      $this->assertNull($result);
-    }
-  }
-
-  /**
-   * Provides data for ::testConvert().
-   */
-  public function providerTestConvert() {
-    $data = [];
-    $data['with value'] = [
-      TRUE,
-      'some_value',
-      'some_value',
-      [],
-    ];
-    $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,
-      '',
-      [],
-    ];
-    return $data;
-  }
-
-  /**
-   * @covers ::convert
-   */
-  public function testConvertCreate() {
-    $expected = 'the_return_value';
-    $value = 'foo.bar.baz';
-    $expected_create_values = [
-      'targetEntityType' => 'foo',
-      'bundle' => 'bar',
-      'mode' => 'baz',
-      'status' => TRUE,
-    ];
-    $entity_storage = $this->prophesize(EntityStorageInterface::class);
-    $entity_storage->load($value)->willReturn(NULL);
-    $entity_storage->create($expected_create_values)->willReturn($expected);
-
-    $this->entityManager->getDefinition('entity_view_display')->willReturn(new EntityType(['id' => 'entity_view_display']));
-    $this->entityManager->getStorage('entity_view_display')->willReturn($entity_storage->reveal());
-
-    $result = $this->converter->convert($value, [], 'the_parameter_name', []);
-    $this->assertSame($expected, $result);
-  }
-
-}
diff --git a/core/modules/layout_builder/tests/src/Unit/SectionStorageManagerTest.php b/core/modules/layout_builder/tests/src/Unit/SectionStorageManagerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..392cd8939ebed61081d53950a127850c72b133bd
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Unit/SectionStorageManagerTest.php
@@ -0,0 +1,100 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\Unit;
+
+use Drupal\Component\Plugin\Factory\FactoryInterface;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\layout_builder\SectionListInterface;
+use Drupal\layout_builder\SectionStorage\SectionStorageManager;
+use Drupal\layout_builder\SectionStorageInterface;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\layout_builder\SectionStorage\SectionStorageManager
+ *
+ * @group layout_builder
+ */
+class SectionStorageManagerTest extends UnitTestCase {
+
+  /**
+   * The section storage manager.
+   *
+   * @var \Drupal\layout_builder\SectionStorage\SectionStorageManager
+   */
+  protected $manager;
+
+  /**
+   * The plugin.
+   *
+   * @var \Drupal\layout_builder\SectionStorageInterface
+   */
+  protected $plugin;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $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());
+  }
+
+  /**
+   * @covers ::loadEmpty
+   */
+  public function testLoadEmpty() {
+    $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);
+  }
+
+  /**
+   * @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);
+  }
+
+  /**
+   * @covers ::loadFromRoute
+   */
+  public function testLoadFromRouteNull() {
+    $this->plugin->extractIdFromRoute('the_value', [], 'the_parameter_name', ['_route' => 'the_route_name'])->willReturn(NULL);
+
+    $result = $this->manager->loadFromRoute('the_plugin_id', 'the_value', [], 'the_parameter_name', ['_route' => 'the_route_name']);
+    $this->assertNull($result);
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Unit/SectionStorageOverridesParamConverterTest.php b/core/modules/layout_builder/tests/src/Unit/SectionStorageOverridesParamConverterTest.php
deleted file mode 100644
index f0c01468e59b1b3578e57e6fb909957b21d434b4..0000000000000000000000000000000000000000
--- a/core/modules/layout_builder/tests/src/Unit/SectionStorageOverridesParamConverterTest.php
+++ /dev/null
@@ -1,119 +0,0 @@
-<?php
-
-namespace Drupal\Tests\layout_builder\Unit;
-
-use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\Core\Entity\EntityType;
-use Drupal\Core\Entity\FieldableEntityInterface;
-use Drupal\layout_builder\Routing\SectionStorageOverridesParamConverter;
-use Drupal\Tests\UnitTestCase;
-use Prophecy\Argument;
-
-/**
- * @coversDefaultClass \Drupal\layout_builder\Routing\SectionStorageOverridesParamConverter
- *
- * @group layout_builder
- */
-class SectionStorageOverridesParamConverterTest extends UnitTestCase {
-
-  /**
-   * The converter.
-   *
-   * @var \Drupal\layout_builder\Routing\SectionStorageOverridesParamConverter
-   */
-  protected $converter;
-
-  /**
-   * The entity manager.
-   *
-   * @var \Drupal\Core\Entity\EntityManagerInterface
-   */
-  protected $entityManager;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp() {
-    parent::setUp();
-
-    $this->entityManager = $this->prophesize(EntityManagerInterface::class);
-    $this->converter = new SectionStorageOverridesParamConverter($this->entityManager->reveal());
-  }
-
-  /**
-   * @covers ::convert
-   * @covers ::getEntityTypeFromDefaults
-   * @covers ::getEntityIdFromDefaults
-   *
-   * @dataProvider providerTestConvert
-   */
-  public function testConvert($success, $expected_entity_type_id, $value, array $defaults) {
-    $defaults['the_parameter_name'] = $value;
-
-    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->entityManager->getDefinition($expected_entity_type_id)->willReturn(new EntityType(['id' => 'entity_view_display']));
-      $this->entityManager->getStorage($expected_entity_type_id)->willReturn($entity_storage->reveal());
-    }
-    else {
-      $this->entityManager->getDefinition(Argument::any())->shouldNotBeCalled();
-      $this->entityManager->getStorage(Argument::any())->shouldNotBeCalled();
-    }
-
-    $result = $this->converter->convert($value, [], 'the_parameter_name', $defaults);
-    if ($success) {
-      $this->assertEquals('the_return_value', $result);
-    }
-    else {
-      $this->assertNull($result);
-    }
-  }
-
-  /**
-   * Provides data for ::testConvert().
-   */
-  public function providerTestConvert() {
-    $data = [];
-    $data['with value, with layout'] = [
-      TRUE,
-      'my_entity_type',
-      'my_entity_type:entity_with_layout',
-      [],
-    ];
-    $data['with value, without layout'] = [
-      FALSE,
-      '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,
-      '',
-      [],
-    ];
-    return $data;
-  }
-
-}