diff --git a/core/modules/layout_builder/config/schema/layout_builder.schema.yml b/core/modules/layout_builder/config/schema/layout_builder.schema.yml
index b870007e33..682caa78c4 100644
--- a/core/modules/layout_builder/config/schema/layout_builder.schema.yml
+++ b/core/modules/layout_builder/config/schema/layout_builder.schema.yml
@@ -5,3 +5,42 @@ core.entity_view_display.*.*.*.third_party.layout_builder:
     allow_custom:
       type: boolean
       label: 'Allow a customized layout'
+    sections:
+      type: sequence
+      sequence:
+        type: layout_builder.section
+
+layout_builder.section:
+  type: mapping
+  label: 'Layout section'
+  mapping:
+    layout_id:
+      type: string
+      label: 'Layout ID'
+    layout_settings:
+      type: layout_plugin.settings.[%parent.layout_id]
+      label: 'Layout settings'
+    components:
+      type: sequence
+      label: 'Components'
+      sequence:
+        type: layout_builder.component
+
+layout_builder.component:
+  type: mapping
+  label: 'Component'
+  mapping:
+    configuration:
+      type: block.settings.[id]
+    region:
+      type: string
+      label: 'Region'
+    uuid:
+      type: uuid
+      label: 'UUID'
+    weight:
+      type: integer
+      label: 'Weight'
+    additional:
+      type: ignore
+      label: 'Additional data'
diff --git a/core/modules/layout_builder/layout_builder.install b/core/modules/layout_builder/layout_builder.install
new file mode 100644
index 0000000000..84997f07b8
--- /dev/null
+++ b/core/modules/layout_builder/layout_builder.install
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Contains install and update functions for Layout Builder.
+ */
+
+use Drupal\Core\Cache\Cache;
+use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
+use Drupal\layout_builder\Section;
+use Drupal\layout_builder\SectionComponent;
+
+/**
+ * Implements hook_install().
+ */
+function layout_builder_install() {
+  $uuid_generator = \Drupal::service('uuid');
+  $entity_field_manager = \Drupal::service('entity_field.manager');
+
+  $displays = LayoutBuilderEntityViewDisplay::loadMultiple();
+  /** @var \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface[] $displays */
+  foreach ($displays as $display) {
+    // Create the first section from any existing Field Layout settings.
+    $field_layout = $display->getThirdPartySettings('field_layout') + [
+      'id' => 'layout_onecol',
+      'settings' => [],
+    ];
+    $components = [];
+    $field_definitions = $entity_field_manager->getFieldDefinitions($display->getTargetEntityTypeId(), $display->getTargetBundle());
+    foreach ($display->getComponents() as $name => $component) {
+      if (isset($field_definitions[$name]) && $field_definitions[$name]->isDisplayConfigurable('view')) {
+        $uuid = $uuid_generator->generate();
+        $configuration = [];
+        $configuration['id'] = 'field_block:' . $display->getTargetEntityTypeId() . ':' . $name;
+        $configuration['formatter']['type'] = $component['type'];
+        $configuration['formatter']['label'] = $component['label'];
+        $configuration['formatter']['settings'] = $component['settings'];
+        $configuration['formatter']['third_party_settings'] = $component['third_party_settings'];
+        $configuration['context_mapping']['entity'] = 'layout_builder.entity';
+        $components[] = (new SectionComponent($uuid, $component['region'], $configuration))->setWeight($component['weight']);
+      }
+    }
+    $display
+      ->appendSection(new Section($field_layout['id'], $field_layout['settings'], $components))
+      ->save();
+  }
+  Cache::invalidateTags(['rendered']);
+}
diff --git a/core/modules/layout_builder/layout_builder.module b/core/modules/layout_builder/layout_builder.module
index 0ba9a21f6b..ae08bd6904 100644
--- a/core/modules/layout_builder/layout_builder.module
+++ b/core/modules/layout_builder/layout_builder.module
@@ -5,12 +5,14 @@
  * Provides hook implementations for Layout Builder.
  */
 
-use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\field\Entity\FieldConfig;
 use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\field_ui\Form\EntityViewDisplayEditForm;
+use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
+use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplayStorage;
+use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
 
 /**
  * Implements hook_help().
@@ -35,13 +37,20 @@ function layout_builder_entity_type_alter(array &$entity_types) {
       $entity_type->setLinkTemplate('layout-builder', $entity_type->getLinkTemplate('canonical') . '/layout');
     }
   }
+  $entity_types['entity_view_display']
+    ->setClass(LayoutBuilderEntityViewDisplay::class)
+    ->setStorageClass(LayoutBuilderEntityViewDisplayStorage::class);
+  if (\Drupal::moduleHandler()->moduleExists('field_ui')) {
+    // @todo Replace this with a custom UI.
+    $entity_types['entity_view_display']->setFormClass('edit', EntityViewDisplayEditForm::class);
+  }
 }
 
 /**
  * Removes the Layout Builder field both visually and from the #fields handling.
  *
- * This prevents any interaction with this field. It is rendered directly
- * in layout_builder_entity_view_alter().
+ * This prevents any interaction with this field. It is rendered directly in
+ * \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::buildMultiple().
  *
  * @internal
  */
@@ -64,7 +73,7 @@ function layout_builder_form_entity_form_display_edit_form_alter(&$form, FormSta
  * Implements hook_form_FORM_ID_alter() for \Drupal\field_ui\Form\EntityViewDisplayEditForm.
  */
 function layout_builder_form_entity_view_display_edit_form_alter(&$form, FormStateInterface $form_state) {
-  /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display */
+  /** @var \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface $display */
   $display = $form_state->getFormObject()->getEntity();
   $entity_type = \Drupal::entityTypeManager()->getDefinition($display->getTargetEntityTypeId());
 
@@ -89,7 +98,7 @@ function layout_builder_form_entity_view_display_edit_form_alter(&$form, FormSta
     '#title' => t('Allow each @entity to have its layout customized.', [
       '@entity' => $entity_type->getSingularLabel(),
     ]),
-    '#default_value' => $display->getThirdPartySetting('layout_builder', 'allow_custom', FALSE),
+    '#default_value' => $display->isOverridable(),
   ];
 
   $form['#entity_builders'][] = 'layout_builder_form_entity_view_display_edit_entity_builder';
@@ -100,17 +109,17 @@ function layout_builder_form_entity_view_display_edit_form_alter(&$form, FormSta
  *
  * @see layout_builder_form_entity_view_display_edit_form_alter()
  */
-function layout_builder_form_entity_view_display_edit_entity_builder($entity_type_id, EntityViewDisplayInterface $display, &$form, FormStateInterface &$form_state) {
+function layout_builder_form_entity_view_display_edit_entity_builder($entity_type_id, LayoutEntityDisplayInterface $display, &$form, FormStateInterface &$form_state) {
   $new_value = (bool) $form_state->getValue(['layout', 'allow_custom'], FALSE);
-  $display->setThirdPartySetting('layout_builder', 'allow_custom', $new_value);
+  $display->setOverridable($new_value);
 }
 
 /**
  * Implements hook_ENTITY_TYPE_presave().
  */
-function layout_builder_entity_view_display_presave(EntityViewDisplayInterface $display) {
-  $original_value = isset($display->original) ? $display->original->getThirdPartySetting('layout_builder', 'allow_custom', FALSE) : FALSE;
-  $new_value = $display->getThirdPartySetting('layout_builder', 'allow_custom', FALSE);
+function layout_builder_entity_view_display_presave(LayoutEntityDisplayInterface $display) {
+  $original_value = isset($display->original) ? $display->original->isOverridable() : FALSE;
+  $new_value = $display->isOverridable();
   if ($original_value !== $new_value) {
     $entity_type_id = $display->getTargetEntityTypeId();
     $bundle = $display->getTargetBundle();
@@ -160,30 +169,3 @@ function layout_builder_add_layout_section_field($entity_type_id, $bundle, $fiel
   }
   return $field;
 }
-
-/**
- * Implements hook_entity_view_alter().
- */
-function layout_builder_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
-  if ($display->getThirdPartySetting('layout_builder', 'allow_custom', FALSE) && !$entity->layout_builder__layout->isEmpty()) {
-    $sections = $entity->layout_builder__layout->getSections();
-    foreach ($sections as $delta => $section) {
-      $build['_layout_builder'][$delta] = $section->toRenderArray();
-    }
-
-    // If field layout is active, that is all that needs to be removed.
-    if (\Drupal::moduleHandler()->moduleExists('field_layout') && isset($build['_field_layout'])) {
-      unset($build['_field_layout']);
-      return;
-    }
-
-    /** @var \Drupal\Core\Field\FieldDefinitionInterface[] $field_definitions */
-    $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions($display->getTargetEntityTypeId(), $display->getTargetBundle());
-    // Remove all display-configurable fields.
-    foreach (array_keys($display->getComponents()) as $name) {
-      if ($name !== 'layout_builder__layout' && isset($field_definitions[$name]) && $field_definitions[$name]->isDisplayConfigurable('view')) {
-        unset($build[$name]);
-      }
-    }
-  }
-}
diff --git a/core/modules/layout_builder/layout_builder.routing.yml b/core/modules/layout_builder/layout_builder.routing.yml
index 8fe952afbe..085eb30111 100644
--- a/core/modules/layout_builder/layout_builder.routing.yml
+++ b/core/modules/layout_builder/layout_builder.routing.yml
@@ -1,5 +1,5 @@
 layout_builder.choose_section:
-  path: '/layout_builder/choose/section/{entity_type_id}/{entity}/{delta}'
+  path: '/layout_builder/choose/section/{section_storage_type}/{section_storage}/{delta}'
   defaults:
    _controller: '\Drupal\layout_builder\Controller\ChooseSectionController::build'
   requirements:
@@ -7,12 +7,11 @@ layout_builder.choose_section:
   options:
     _admin_route: TRUE
     parameters:
-      entity:
-        type: entity:{entity_type_id}
+      section_storage:
         layout_builder_tempstore: TRUE
 
 layout_builder.add_section:
-  path: '/layout_builder/add/section/{entity_type_id}/{entity}/{delta}/{plugin_id}'
+  path: '/layout_builder/add/section/{section_storage_type}/{section_storage}/{delta}/{plugin_id}'
   defaults:
     _controller: '\Drupal\layout_builder\Controller\AddSectionController::build'
   requirements:
@@ -20,12 +19,11 @@ layout_builder.add_section:
   options:
     _admin_route: TRUE
     parameters:
-      entity:
-        type: entity:{entity_type_id}
+      section_storage:
         layout_builder_tempstore: TRUE
 
 layout_builder.configure_section:
-  path: '/layout_builder/configure/section/{entity_type_id}/{entity}/{delta}/{plugin_id}'
+  path: '/layout_builder/configure/section/{section_storage_type}/{section_storage}/{delta}/{plugin_id}'
   defaults:
     _title: 'Configure section'
     _form: '\Drupal\layout_builder\Form\ConfigureSectionForm'
@@ -37,12 +35,11 @@ layout_builder.configure_section:
   options:
     _admin_route: TRUE
     parameters:
-      entity:
-        type: entity:{entity_type_id}
+      section_storage:
         layout_builder_tempstore: TRUE
 
 layout_builder.remove_section:
-  path: '/layout_builder/remove/section/{entity_type_id}/{entity}/{delta}'
+  path: '/layout_builder/remove/section/{section_storage_type}/{section_storage}/{delta}'
   defaults:
     _form: '\Drupal\layout_builder\Form\RemoveSectionForm'
   requirements:
@@ -50,12 +47,11 @@ layout_builder.remove_section:
   options:
     _admin_route: TRUE
     parameters:
-      entity:
-        type: entity:{entity_type_id}
+      section_storage:
         layout_builder_tempstore: TRUE
 
 layout_builder.choose_block:
-  path: '/layout_builder/choose/block/{entity_type_id}/{entity}/{delta}/{region}'
+  path: '/layout_builder/choose/block/{section_storage_type}/{section_storage}/{delta}/{region}'
   defaults:
     _controller: '\Drupal\layout_builder\Controller\ChooseBlockController::build'
   requirements:
@@ -63,12 +59,11 @@ layout_builder.choose_block:
   options:
     _admin_route: TRUE
     parameters:
-      entity:
-        type: entity:{entity_type_id}
+      section_storage:
         layout_builder_tempstore: TRUE
 
 layout_builder.add_block:
-  path: '/layout_builder/add/block/{entity_type_id}/{entity}/{delta}/{region}/{plugin_id}'
+  path: '/layout_builder/add/block/{section_storage_type}/{section_storage}/{delta}/{region}/{plugin_id}'
   defaults:
     _form: '\Drupal\layout_builder\Form\AddBlockForm'
   requirements:
@@ -76,12 +71,11 @@ layout_builder.add_block:
   options:
     _admin_route: TRUE
     parameters:
-      entity:
-        type: entity:{entity_type_id}
+      section_storage:
         layout_builder_tempstore: TRUE
 
 layout_builder.update_block:
-  path: '/layout_builder/update/block/{entity_type_id}/{entity}/{delta}/{region}/{uuid}'
+  path: '/layout_builder/update/block/{section_storage_type}/{section_storage}/{delta}/{region}/{uuid}'
   defaults:
     _form: '\Drupal\layout_builder\Form\UpdateBlockForm'
   requirements:
@@ -89,12 +83,11 @@ layout_builder.update_block:
   options:
     _admin_route: TRUE
     parameters:
-      entity:
-        type: entity:{entity_type_id}
+      section_storage:
         layout_builder_tempstore: TRUE
 
 layout_builder.remove_block:
-  path: '/layout_builder/remove/block/{entity_type_id}/{entity}/{delta}/{region}/{uuid}'
+  path: '/layout_builder/remove/block/{section_storage_type}/{section_storage}/{delta}/{region}/{uuid}'
   defaults:
     _form: '\Drupal\layout_builder\Form\RemoveBlockForm'
   requirements:
@@ -102,12 +95,11 @@ layout_builder.remove_block:
   options:
     _admin_route: TRUE
     parameters:
-      entity:
-        type: entity:{entity_type_id}
+      section_storage:
         layout_builder_tempstore: TRUE
 
 layout_builder.move_block:
-  path: '/layout_builder/move/block/{entity_type_id}/{entity}/{delta_from}/{delta_to}/{region_from}/{region_to}/{block_uuid}/{preceding_block_uuid}'
+  path: '/layout_builder/move/block/{section_storage_type}/{section_storage}/{delta_from}/{delta_to}/{region_from}/{region_to}/{block_uuid}/{preceding_block_uuid}'
   defaults:
     _controller: '\Drupal\layout_builder\Controller\MoveBlockController::build'
     delta_from: null
@@ -121,8 +113,7 @@ layout_builder.move_block:
   options:
     _admin_route: TRUE
     parameters:
-      entity:
-        type: entity:{entity_type_id}
+      section_storage:
         layout_builder_tempstore: TRUE
 
 route_callbacks:
diff --git a/core/modules/layout_builder/layout_builder.services.yml b/core/modules/layout_builder/layout_builder.services.yml
index b71f6b1887..ff07056d8d 100644
--- a/core/modules/layout_builder/layout_builder.services.yml
+++ b/core/modules/layout_builder/layout_builder.services.yml
@@ -1,7 +1,7 @@
 services:
   layout_builder.tempstore_repository:
     class: Drupal\layout_builder\LayoutTempstoreRepository
-    arguments: ['@user.shared_tempstore', '@entity_type.manager']
+    arguments: ['@user.shared_tempstore']
   access_check.entity.layout:
     class: Drupal\layout_builder\Access\LayoutSectionAccessCheck
     tags:
@@ -9,15 +9,23 @@ services:
   layout_builder.routes:
     class: Drupal\layout_builder\Routing\LayoutBuilderRoutes
     arguments: ['@entity_type.manager', '@entity_field.manager']
+    tags:
+     - { name: event_subscriber }
   layout_builder.route_enhancer:
     class: Drupal\layout_builder\Routing\LayoutBuilderRouteEnhancer
     tags:
       - { name: route_enhancer }
   layout_builder.param_converter:
     class: Drupal\layout_builder\Routing\LayoutTempstoreParamConverter
-    arguments: ['@entity.manager', '@layout_builder.tempstore_repository']
+    arguments: ['@layout_builder.tempstore_repository', '@class_resolver']
     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']
diff --git a/core/modules/layout_builder/src/Access/LayoutSectionAccessCheck.php b/core/modules/layout_builder/src/Access/LayoutSectionAccessCheck.php
index 231a70fac5..3f157f8ee0 100644
--- a/core/modules/layout_builder/src/Access/LayoutSectionAccessCheck.php
+++ b/core/modules/layout_builder/src/Access/LayoutSectionAccessCheck.php
@@ -3,10 +3,10 @@
 namespace Drupal\layout_builder\Access;
 
 use Drupal\Core\Access\AccessResult;
-use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Routing\Access\AccessInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\layout_builder\SectionStorageInterface;
 
 /**
  * Provides an access check for the Layout Builder UI.
@@ -16,7 +16,7 @@
 class LayoutSectionAccessCheck implements AccessInterface {
 
   /**
-   * Checks routing access to layout for the entity.
+   * Checks routing access to the layout.
    *
    * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
    *   The current route match.
@@ -27,24 +27,20 @@ class LayoutSectionAccessCheck implements AccessInterface {
    *   The access result.
    */
   public function access(RouteMatchInterface $route_match, AccountInterface $account) {
-    // Attempt to retrieve the generic 'entity' parameter, otherwise look up the
-    // specific entity via the entity type ID.
-    $entity = $route_match->getParameter('entity') ?: $route_match->getParameter($route_match->getParameter('entity_type_id'));
+    $section_storage = $route_match->getParameter('section_storage');
 
-    // If we don't have an entity, forbid access.
-    if (empty($entity)) {
+    if (empty($section_storage)) {
       return AccessResult::forbidden()->addCacheContexts(['route']);
     }
 
-    // If the entity isn't fieldable, forbid access.
-    if (!$entity instanceof FieldableEntityInterface || !$entity->hasField('layout_builder__layout')) {
+    if (!$section_storage instanceof SectionStorageInterface) {
       $access = AccessResult::forbidden();
     }
     else {
       $access = AccessResult::allowedIfHasPermission($account, 'configure any layout');
     }
 
-    return $access->addCacheableDependency($entity);
+    return $access->addCacheableDependency($section_storage);
   }
 
 }
diff --git a/core/modules/layout_builder/src/Cache/LayoutBuilderIsActiveCacheContext.php b/core/modules/layout_builder/src/Cache/LayoutBuilderIsActiveCacheContext.php
index c632f4b33a..3c3bc25c40 100644
--- a/core/modules/layout_builder/src/Cache/LayoutBuilderIsActiveCacheContext.php
+++ b/core/modules/layout_builder/src/Cache/LayoutBuilderIsActiveCacheContext.php
@@ -4,8 +4,8 @@
 
 use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Cache\Context\CalculatedCacheContextInterface;
-use Drupal\Core\Entity\Entity\EntityViewDisplay;
 use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\layout_builder\OverridesSectionStorageInterface;
 
 /**
  * Determines whether Layout Builder is active for a given entity type or not.
@@ -49,7 +49,7 @@ public function getContext($entity_type_id = NULL) {
     }
 
     $display = $this->getDisplay($entity_type_id);
-    return ($display && $display->getThirdPartySetting('layout_builder', 'allow_custom', FALSE)) ? '1' : '0';
+    return ($display && $display->isOverridable()) ? '1' : '0';
   }
 
   /**
@@ -72,15 +72,15 @@ public function getCacheableMetadata($entity_type_id = NULL) {
    *
    * @param string $entity_type_id
    *   The entity type ID.
-   * @param string $view_mode
-   *   (optional) The view mode that should be used to render the entity.
    *
-   * @return \Drupal\Core\Entity\Display\EntityViewDisplayInterface|null
+   * @return \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface|null
    *   The entity view display, if it exists.
    */
-  protected function getDisplay($entity_type_id, $view_mode = 'full') {
+  protected function getDisplay($entity_type_id) {
     if ($entity = $this->routeMatch->getParameter($entity_type_id)) {
-      return EntityViewDisplay::collectRenderDisplay($entity, $view_mode);
+      if ($entity instanceof OverridesSectionStorageInterface) {
+        return $entity->getDefaultSectionStorage();
+      }
     }
   }
 
diff --git a/core/modules/layout_builder/src/Context/LayoutBuilderContextTrait.php b/core/modules/layout_builder/src/Context/LayoutBuilderContextTrait.php
new file mode 100644
index 0000000000..3c16332def
--- /dev/null
+++ b/core/modules/layout_builder/src/Context/LayoutBuilderContextTrait.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Drupal\layout_builder\Context;
+
+use Drupal\Core\Plugin\Context\ContextInterface;
+use Drupal\layout_builder\SectionStorageInterface;
+
+/**
+ * Provides a wrapper around getting contexts from a section storage object.
+ */
+trait LayoutBuilderContextTrait {
+
+  /**
+   * The context repository.
+   *
+   * @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface
+   */
+  protected $contextRepository;
+
+  /**
+   * Gets the context repository service.
+   *
+   * @return \Drupal\Core\Plugin\Context\ContextRepositoryInterface
+   *   The context repository service.
+   */
+  protected function contextRepository() {
+    if (!$this->contextRepository) {
+      $this->contextRepository = \Drupal::service('context.repository');
+    }
+    return $this->contextRepository;
+  }
+
+  /**
+   * Provides all available contexts, both global and section_storage-specific.
+   *
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
+   *
+   * @return \Drupal\Core\Plugin\Context\ContextInterface[]
+   *   The array of context objects.
+   */
+  protected function getAvailableContexts(SectionStorageInterface $section_storage) {
+    // Get all globally available contexts that have a defined value.
+    $contexts = array_filter($this->contextRepository()->getAvailableContexts(), function (ContextInterface $context) {
+      return $context->hasContextValue();
+    });
+
+    // Add in the per-section_storage contexts.
+    $contexts += $section_storage->getContexts();
+    return $contexts;
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Context/SectionStorageEntityContextTrait.php b/core/modules/layout_builder/src/Context/SectionStorageEntityContextTrait.php
new file mode 100644
index 0000000000..410b193241
--- /dev/null
+++ b/core/modules/layout_builder/src/Context/SectionStorageEntityContextTrait.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Drupal\layout_builder\Context;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Plugin\Context\Context;
+use Drupal\Core\Plugin\Context\ContextDefinition;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Provides contexts for any entity-based section storage.
+ */
+trait SectionStorageEntityContextTrait {
+
+  /**
+   * Produces contexts for the entity.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity being laid out.
+   *
+   * @return \Drupal\Core\Plugin\Context\ContextInterface[]
+   *   The array of context objects.
+   */
+  protected function getEntityContexts(EntityInterface $entity) {
+    $contexts = [];
+    // Create a new context for the entity we're currently dealing with.
+    // @todo Use EntityContextDefinition after resolving
+    //   https://www.drupal.org/node/2932462.
+    $definition = new ContextDefinition("entity:{$entity->getEntityTypeId()}", new TranslatableMarkup('Current @entity', [
+      '@entity' => $entity->getEntityType()->getSingularLabel(),
+    ]));
+    $context = new Context($definition, $entity);
+    $contexts['layout_builder.entity'] = $context;
+    return $contexts;
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Controller/AddSectionController.php b/core/modules/layout_builder/src/Controller/AddSectionController.php
index fa522b5472..947895985c 100644
--- a/core/modules/layout_builder/src/Controller/AddSectionController.php
+++ b/core/modules/layout_builder/src/Controller/AddSectionController.php
@@ -4,9 +4,9 @@
 
 use Drupal\Core\DependencyInjection\ClassResolverInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Drupal\layout_builder\Section;
+use Drupal\layout_builder\SectionStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
@@ -51,10 +51,10 @@ public static function create(ContainerInterface $container) {
   }
 
   /**
-   * Add the layout to the entity field in a tempstore.
+   * Adds the new section.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
    * @param int $delta
    *   The delta of the section to splice.
    * @param string $plugin_id
@@ -63,18 +63,16 @@ public static function create(ContainerInterface $container) {
    * @return \Symfony\Component\HttpFoundation\Response
    *   The controller response.
    */
-  public function build(EntityInterface $entity, $delta, $plugin_id) {
-    /** @var \Drupal\layout_builder\SectionStorageInterface $field_list */
-    $field_list = $entity->layout_builder__layout;
-    $field_list->insertSection($delta, new Section($plugin_id));
+  public function build(SectionStorageInterface $section_storage, $delta, $plugin_id) {
+    $section_storage->insertSection($delta, new Section($plugin_id));
 
-    $this->layoutTempstoreRepository->set($entity);
+    $this->layoutTempstoreRepository->set($section_storage);
 
     if ($this->isAjax()) {
-      return $this->rebuildAndClose($entity);
+      return $this->rebuildAndClose($section_storage);
     }
     else {
-      $url = $entity->toUrl('layout-builder');
+      $url = $section_storage->getLayoutBuilderUrl();
       return new RedirectResponse($url->setAbsolute()->toString());
     }
   }
diff --git a/core/modules/layout_builder/src/Controller/ChooseBlockController.php b/core/modules/layout_builder/src/Controller/ChooseBlockController.php
index 9eddb79fc3..db80a9ef23 100644
--- a/core/modules/layout_builder/src/Controller/ChooseBlockController.php
+++ b/core/modules/layout_builder/src/Controller/ChooseBlockController.php
@@ -4,8 +4,10 @@
 
 use Drupal\Core\Block\BlockManagerInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
 use Drupal\Core\Url;
+use Drupal\layout_builder\Context\LayoutBuilderContextTrait;
+use Drupal\layout_builder\SectionStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -16,6 +18,7 @@
 class ChooseBlockController implements ContainerInjectionInterface {
 
   use AjaxHelperTrait;
+  use LayoutBuilderContextTrait;
 
   /**
    * The block manager.
@@ -24,14 +27,24 @@ class ChooseBlockController implements ContainerInjectionInterface {
    */
   protected $blockManager;
 
+  /**
+   * The context repository.
+   *
+   * @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface
+   */
+  protected $contextRepository;
+
   /**
    * ChooseBlockController constructor.
    *
    * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
    *   The block manager.
+   * @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository
+   *   The context repository.
    */
-  public function __construct(BlockManagerInterface $block_manager) {
+  public function __construct(BlockManagerInterface $block_manager, ContextRepositoryInterface $context_repository) {
     $this->blockManager = $block_manager;
+    $this->contextRepository = $context_repository;
   }
 
   /**
@@ -39,15 +52,16 @@ public function __construct(BlockManagerInterface $block_manager) {
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('plugin.manager.block')
+      $container->get('plugin.manager.block'),
+      $container->get('context.repository')
     );
   }
 
   /**
    * Provides the UI for choosing a new block.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
    * @param int $delta
    *   The delta of the section to splice.
    * @param string $region
@@ -56,11 +70,13 @@ public static function create(ContainerInterface $container) {
    * @return array
    *   A render array.
    */
-  public function build(EntityInterface $entity, $delta, $region) {
+  public function build(SectionStorageInterface $section_storage, $delta, $region) {
     $build['#type'] = 'container';
     $build['#attributes']['class'][] = 'block-categories';
 
-    foreach ($this->blockManager->getGroupedDefinitions() as $category => $blocks) {
+    $contexts = $this->getAvailableContexts($section_storage);
+    $definitions = $this->blockManager->getDefinitionsForContexts($contexts);
+    foreach ($this->blockManager->getGroupedDefinitions($definitions) as $category => $blocks) {
       $build[$category]['#type'] = 'details';
       $build[$category]['#open'] = TRUE;
       $build[$category]['#title'] = $category;
@@ -72,8 +88,8 @@ public function build(EntityInterface $entity, $delta, $region) {
           'title' => $block['admin_label'],
           'url' => Url::fromRoute('layout_builder.add_block',
             [
-              'entity_type_id' => $entity->getEntityTypeId(),
-              'entity' => $entity->id(),
+              'section_storage_type' => $section_storage->getStorageType(),
+              'section_storage' => $section_storage->getStorageId(),
               'delta' => $delta,
               'region' => $region,
               'plugin_id' => $block_id,
diff --git a/core/modules/layout_builder/src/Controller/ChooseSectionController.php b/core/modules/layout_builder/src/Controller/ChooseSectionController.php
index 0414d2abf1..a04cdbb1c1 100644
--- a/core/modules/layout_builder/src/Controller/ChooseSectionController.php
+++ b/core/modules/layout_builder/src/Controller/ChooseSectionController.php
@@ -3,11 +3,11 @@
 namespace Drupal\layout_builder\Controller;
 
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Layout\LayoutPluginManagerInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\Url;
+use Drupal\layout_builder\SectionStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -49,15 +49,15 @@ public static function create(ContainerInterface $container) {
   /**
    * Choose a layout plugin to add as a section.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
    * @param int $delta
    *   The delta of the section to splice.
    *
    * @return array
    *   The render array.
    */
-  public function build(EntityInterface $entity, $delta) {
+  public function build(SectionStorageInterface $section_storage, $delta) {
     $output['#title'] = $this->t('Choose a layout');
 
     $items = [];
@@ -75,8 +75,8 @@ public function build(EntityInterface $entity, $delta) {
         '#url' => Url::fromRoute(
           $layout instanceof PluginFormInterface ? 'layout_builder.configure_section' : 'layout_builder.add_section',
           [
-            'entity_type_id' => $entity->getEntityTypeId(),
-            'entity' => $entity->id(),
+            'section_storage_type' => $section_storage->getStorageType(),
+            'section_storage' => $section_storage->getStorageId(),
             'delta' => $delta,
             'plugin_id' => $plugin_id,
           ]
diff --git a/core/modules/layout_builder/src/Controller/LayoutBuilderController.php b/core/modules/layout_builder/src/Controller/LayoutBuilderController.php
index 9e09a61c6d..97f2c7af1f 100644
--- a/core/modules/layout_builder/src/Controller/LayoutBuilderController.php
+++ b/core/modules/layout_builder/src/Controller/LayoutBuilderController.php
@@ -3,12 +3,14 @@
 namespace Drupal\layout_builder\Controller;
 
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\Url;
+use Drupal\layout_builder\Context\LayoutBuilderContextTrait;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
+use Drupal\layout_builder\OverridesSectionStorageInterface;
 use Drupal\layout_builder\Section;
+use Drupal\layout_builder\SectionStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
@@ -19,6 +21,7 @@
  */
 class LayoutBuilderController implements ContainerInjectionInterface {
 
+  use LayoutBuilderContextTrait;
   use StringTranslationTrait;
 
   /**
@@ -50,48 +53,38 @@ public static function create(ContainerInterface $container) {
   /**
    * Provides a title callback.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
    *
    * @return string
    *   The title for the layout page.
    */
-  public function title(EntityInterface $entity) {
-    return $this->t('Edit layout for %label', ['%label' => $entity->label()]);
+  public function title(SectionStorageInterface $section_storage) {
+    return $this->t('Edit layout for %label', ['%label' => $section_storage->label()]);
   }
 
   /**
    * Renders the Layout UI.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
    * @param bool $is_rebuilding
    *   (optional) Indicates if the layout is rebuilding, defaults to FALSE.
    *
    * @return array
    *   A render array.
    */
-  public function layout(EntityInterface $entity, $is_rebuilding = FALSE) {
-    $entity_id = $entity->id();
-    $entity_type_id = $entity->getEntityTypeId();
-
-    /** @var \Drupal\layout_builder\SectionStorageInterface $field_list */
-    $field_list = $entity->layout_builder__layout;
-
-    // For a new layout override, begin with a single section of one column.
-    if (!$is_rebuilding && $field_list->count() === 0) {
-      $field_list->appendSection(new Section('layout_onecol'));
-      $this->layoutTempstoreRepository->set($entity);
-    }
+  public function layout(SectionStorageInterface $section_storage, $is_rebuilding = FALSE) {
+    $this->prepareLayout($section_storage, $is_rebuilding);
 
     $output = [];
     $count = 0;
-    foreach ($field_list->getSections() as $section) {
-      $output[] = $this->buildAddSectionLink($entity_type_id, $entity_id, $count);
-      $output[] = $this->buildAdministrativeSection($section, $entity, $count);
+    for ($i = 0; $i < $section_storage->count(); $i++) {
+      $output[] = $this->buildAddSectionLink($section_storage, $count);
+      $output[] = $this->buildAdministrativeSection($section_storage, $count);
       $count++;
     }
-    $output[] = $this->buildAddSectionLink($entity_type_id, $entity_id, $count);
+    $output[] = $this->buildAddSectionLink($section_storage, $count);
     $output['#attached']['library'][] = 'layout_builder/drupal.layout_builder';
     $output['#type'] = 'container';
     $output['#attributes']['id'] = 'layout-builder';
@@ -100,28 +93,58 @@ public function layout(EntityInterface $entity, $is_rebuilding = FALSE) {
     return $output;
   }
 
+  /**
+   * Prepares a layout for use in the UI.
+   *
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
+   * @param bool $is_rebuilding
+   *   Indicates if the layout is rebuilding.
+   */
+  protected function prepareLayout(SectionStorageInterface $section_storage, $is_rebuilding) {
+    // For a new layout, begin with a single section of one column.
+    if (!$is_rebuilding && $section_storage->count() === 0) {
+      $sections = [];
+      // If this is an empty override, copy the sections from the corresponding
+      // default.
+      if ($section_storage instanceof OverridesSectionStorageInterface) {
+        $display = $section_storage->getDefaultSectionStorage();
+        $sections = $display->getSections();
+      }
+
+      if (!$sections) {
+        $sections[] = new Section('layout_onecol');
+      }
+
+      foreach ($sections as $section) {
+        $section_storage->appendSection($section);
+      }
+      $this->layoutTempstoreRepository->set($section_storage);
+    }
+  }
+
   /**
    * Builds a link to add a new section at a given delta.
    *
-   * @param string $entity_type_id
-   *   The entity type.
-   * @param string $entity_id
-   *   The entity ID.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
    * @param int $delta
    *   The delta of the section to splice.
    *
    * @return array
    *   A render array for a link.
    */
-  protected function buildAddSectionLink($entity_type_id, $entity_id, $delta) {
+  protected function buildAddSectionLink(SectionStorageInterface $section_storage, $delta) {
+    $storage_type = $section_storage->getStorageType();
+    $storage_id = $section_storage->getStorageId();
     return [
       'link' => [
         '#type' => 'link',
         '#title' => $this->t('Add Section'),
         '#url' => Url::fromRoute('layout_builder.choose_section',
           [
-            'entity_type_id' => $entity_type_id,
-            'entity' => $entity_id,
+            'section_storage_type' => $storage_type,
+            'section_storage' => $storage_id,
             'delta' => $delta,
           ],
           [
@@ -143,22 +166,21 @@ protected function buildAddSectionLink($entity_type_id, $entity_id, $delta) {
   /**
    * Builds the render array for the layout section while editing.
    *
-   * @param \Drupal\layout_builder\Section $section
-   *   The layout section.
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
    * @param int $delta
    *   The delta of the section.
    *
    * @return array
    *   The render array for a given section.
    */
-  protected function buildAdministrativeSection(Section $section, EntityInterface $entity, $delta) {
-    $entity_type_id = $entity->getEntityTypeId();
-    $entity_id = $entity->id();
+  protected function buildAdministrativeSection(SectionStorageInterface $section_storage, $delta) {
+    $storage_type = $section_storage->getStorageType();
+    $storage_id = $section_storage->getStorageId();
+    $section = $section_storage->getSection($delta);
 
     $layout = $section->getLayout();
-    $build = $section->toRenderArray();
+    $build = $section->toRenderArray($this->getAvailableContexts($section_storage));
     $layout_definition = $layout->getPluginDefinition();
 
     foreach ($layout_definition->getRegions() as $region => $info) {
@@ -169,8 +191,8 @@ protected function buildAdministrativeSection(Section $section, EntityInterface
           $build[$region][$uuid]['#contextual_links'] = [
             'layout_builder_block' => [
               'route_parameters' => [
-                'entity_type_id' => $entity_type_id,
-                'entity' => $entity_id,
+                'section_storage_type' => $storage_type,
+                'section_storage' => $storage_id,
                 'delta' => $delta,
                 'region' => $region,
                 'uuid' => $uuid,
@@ -185,8 +207,8 @@ protected function buildAdministrativeSection(Section $section, EntityInterface
         '#title' => $this->t('Add Block'),
         '#url' => Url::fromRoute('layout_builder.choose_block',
           [
-            'entity_type_id' => $entity_type_id,
-            'entity' => $entity_id,
+            'section_storage_type' => $storage_type,
+            'section_storage' => $storage_id,
             'delta' => $delta,
             'region' => $region,
           ],
@@ -207,8 +229,8 @@ protected function buildAdministrativeSection(Section $section, EntityInterface
     }
 
     $build['#attributes']['data-layout-update-url'] = Url::fromRoute('layout_builder.move_block', [
-      'entity_type_id' => $entity_type_id,
-      'entity' => $entity_id,
+      'section_storage_type' => $storage_type,
+      'section_storage' => $storage_id,
     ])->toString();
     $build['#attributes']['data-layout-delta'] = $delta;
     $build['#attributes']['class'][] = 'layout-builder--layout';
@@ -223,8 +245,8 @@ protected function buildAdministrativeSection(Section $section, EntityInterface
         '#title' => $this->t('Configure section'),
         '#access' => $layout instanceof PluginFormInterface,
         '#url' => Url::fromRoute('layout_builder.configure_section', [
-          'entity_type_id' => $entity_type_id,
-          'entity' => $entity_id,
+          'section_storage_type' => $storage_type,
+          'section_storage' => $storage_id,
           'delta' => $delta,
         ]),
         '#attributes' => [
@@ -237,8 +259,8 @@ protected function buildAdministrativeSection(Section $section, EntityInterface
         '#type' => 'link',
         '#title' => $this->t('Remove section'),
         '#url' => Url::fromRoute('layout_builder.remove_section', [
-          'entity_type_id' => $entity_type_id,
-          'entity' => $entity_id,
+          'section_storage_type' => $storage_type,
+          'section_storage' => $storage_id,
           'delta' => $delta,
         ]),
         '#attributes' => [
@@ -254,30 +276,30 @@ protected function buildAdministrativeSection(Section $section, EntityInterface
   /**
    * Saves the layout.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
    *
    * @return \Symfony\Component\HttpFoundation\RedirectResponse
    *   A redirect response.
    */
-  public function saveLayout(EntityInterface $entity) {
-    $entity->save();
-    $this->layoutTempstoreRepository->delete($entity);
-    return new RedirectResponse($entity->toUrl()->setAbsolute()->toString());
+  public function saveLayout(SectionStorageInterface $section_storage) {
+    $section_storage->save();
+    $this->layoutTempstoreRepository->delete($section_storage);
+    return new RedirectResponse($section_storage->getCanonicalUrl()->setAbsolute()->toString());
   }
 
   /**
    * Cancels the layout.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
    *
    * @return \Symfony\Component\HttpFoundation\RedirectResponse
    *   A redirect response.
    */
-  public function cancelLayout(EntityInterface $entity) {
-    $this->layoutTempstoreRepository->delete($entity);
-    return new RedirectResponse($entity->toUrl()->setAbsolute()->toString());
+  public function cancelLayout(SectionStorageInterface $section_storage) {
+    $this->layoutTempstoreRepository->delete($section_storage);
+    return new RedirectResponse($section_storage->getCanonicalUrl()->setAbsolute()->toString());
   }
 
 }
diff --git a/core/modules/layout_builder/src/Controller/LayoutRebuildTrait.php b/core/modules/layout_builder/src/Controller/LayoutRebuildTrait.php
index 53fd4e8b0a..3fac020770 100644
--- a/core/modules/layout_builder/src/Controller/LayoutRebuildTrait.php
+++ b/core/modules/layout_builder/src/Controller/LayoutRebuildTrait.php
@@ -5,7 +5,7 @@
 use Drupal\Core\Ajax\AjaxResponse;
 use Drupal\Core\Ajax\CloseDialogCommand;
 use Drupal\Core\Ajax\ReplaceCommand;
-use Drupal\Core\Entity\EntityInterface;
+use Drupal\layout_builder\SectionStorageInterface;
 
 /**
  * Provides AJAX responses to rebuild the Layout Builder.
@@ -24,15 +24,15 @@
   /**
    * Rebuilds the layout.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
    *
    * @return \Drupal\Core\Ajax\AjaxResponse
    *   An AJAX response to either rebuild the layout and close the dialog, or
    *   reload the page.
    */
-  protected function rebuildAndClose(EntityInterface $entity) {
-    $response = $this->rebuildLayout($entity);
+  protected function rebuildAndClose(SectionStorageInterface $section_storage) {
+    $response = $this->rebuildLayout($section_storage);
     $response->addCommand(new CloseDialogCommand('#drupal-off-canvas'));
     return $response;
   }
@@ -40,17 +40,17 @@ protected function rebuildAndClose(EntityInterface $entity) {
   /**
    * Rebuilds the layout.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
    *
    * @return \Drupal\Core\Ajax\AjaxResponse
    *   An AJAX response to either rebuild the layout and close the dialog, or
    *   reload the page.
    */
-  protected function rebuildLayout(EntityInterface $entity) {
+  protected function rebuildLayout(SectionStorageInterface $section_storage) {
     $response = new AjaxResponse();
     $layout_controller = $this->classResolver->getInstanceFromDefinition(LayoutBuilderController::class);
-    $layout = $layout_controller->layout($entity, TRUE);
+    $layout = $layout_controller->layout($section_storage, TRUE);
     $response->addCommand(new ReplaceCommand('#layout-builder', $layout));
     return $response;
   }
diff --git a/core/modules/layout_builder/src/Controller/MoveBlockController.php b/core/modules/layout_builder/src/Controller/MoveBlockController.php
index 7a841a252d..7411aa0bbe 100644
--- a/core/modules/layout_builder/src/Controller/MoveBlockController.php
+++ b/core/modules/layout_builder/src/Controller/MoveBlockController.php
@@ -4,8 +4,8 @@
 
 use Drupal\Core\DependencyInjection\ClassResolverInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
+use Drupal\layout_builder\SectionStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -50,8 +50,8 @@ public static function create(ContainerInterface $container) {
   /**
    * Moves a block to another region.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
    * @param int $delta_from
    *   The delta of the original section.
    * @param int $delta_to
@@ -68,10 +68,8 @@ public static function create(ContainerInterface $container) {
    * @return \Drupal\Core\Ajax\AjaxResponse
    *   An AJAX response.
    */
-  public function build(EntityInterface $entity, $delta_from, $delta_to, $region_from, $region_to, $block_uuid, $preceding_block_uuid = NULL) {
-    /** @var \Drupal\layout_builder\SectionStorageInterface $field_list */
-    $field_list = $entity->layout_builder__layout;
-    $section = $field_list->getSection($delta_from);
+  public function build(SectionStorageInterface $section_storage, $delta_from, $delta_to, $region_from, $region_to, $block_uuid, $preceding_block_uuid = NULL) {
+    $section = $section_storage->getSection($delta_from);
 
     $component = $section->getComponent($block_uuid);
     $section->removeComponent($block_uuid);
@@ -79,7 +77,7 @@ public function build(EntityInterface $entity, $delta_from, $delta_to, $region_f
     // If the block is moving from one section to another, update the original
     // section and load the new one.
     if ($delta_from !== $delta_to) {
-      $section = $field_list->getSection($delta_to);
+      $section = $section_storage->getSection($delta_to);
     }
 
     // If a preceding block was specified, insert after that. Otherwise add the
@@ -92,8 +90,8 @@ public function build(EntityInterface $entity, $delta_from, $delta_to, $region_f
       $section->appendComponent($component);
     }
 
-    $this->layoutTempstoreRepository->set($entity);
-    return $this->rebuildLayout($entity);
+    $this->layoutTempstoreRepository->set($section_storage);
+    return $this->rebuildLayout($section_storage);
   }
 
 }
diff --git a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
new file mode 100644
index 0000000000..c7775811d5
--- /dev/null
+++ b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
@@ -0,0 +1,313 @@
+<?php
+
+namespace Drupal\layout_builder\Entity;
+
+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\layout_builder\Context\SectionStorageEntityContextTrait;
+use Drupal\layout_builder\Section;
+
+/**
+ * Provides an entity view display entity that has a layout.
+ *
+ * @internal
+ */
+class LayoutBuilderEntityViewDisplay extends BaseEntityViewDisplay implements LayoutEntityDisplayInterface {
+
+  use SectionStorageEntityContextTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isOverridable() {
+    return $this->getThirdPartySetting('layout_builder', 'allow_custom', FALSE);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setOverridable($overridable = TRUE) {
+    $this->setThirdPartySetting('layout_builder', 'allow_custom', $overridable);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSections() {
+    return $this->getThirdPartySetting('layout_builder', 'sections', []);
+  }
+
+  /**
+   * Store the information for all sections.
+   *
+   * @param \Drupal\layout_builder\Section[] $sections
+   *   The sections information.
+   *
+   * @return $this
+   */
+  protected function setSections(array $sections) {
+    $this->setThirdPartySetting('layout_builder', 'sections', $sections);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function count() {
+    return count($this->getSections());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSection($delta) {
+    $sections = $this->getSections();
+    if (!isset($sections[$delta])) {
+      throw new \OutOfBoundsException(sprintf('Invalid delta "%s" for the "%s" entity', $delta, $this->id()));
+    }
+    return $sections[$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) {
+    $sections = $this->getSections();
+    if (isset($sections[$delta])) {
+      // @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(array_values($sections));
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function urlRouteParameters($rel) {
+    $route_parameters = parent::urlRouteParameters($rel);
+
+    // @todo Move this to \Drupal\Core\Entity\EntityDisplayBase.
+    $entity_type = $this->entityTypeManager()->getDefinition($this->getTargetEntityTypeId());
+    $bundle_parameter_key = $entity_type->getBundleEntityType() ?: 'bundle';
+    $route_parameters[$bundle_parameter_key] = $this->getTargetBundle();
+    return $route_parameters;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function linkTemplates() {
+    $link_templates = parent::linkTemplates();
+    $link_templates[$this->getTargetEntityTypeId() . '.layout-builder'] = TRUE;
+    return $link_templates;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function toUrl($rel = 'edit-form', array $options = []) {
+    if ($rel === 'canonical') {
+      $rel = 'layout-builder';
+    }
+
+    if ($rel === 'layout-builder') {
+      $rel = $this->getTargetEntityTypeId() . '.' . $rel;
+    }
+    return parent::toUrl($rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preSave(EntityStorageInterface $storage) {
+    parent::preSave($storage);
+
+    // Ensure the plugin configuration is updated. Once layouts are no longer
+    // stored as third party settings, this will be handled by the code in
+    // \Drupal\Core\Config\Entity\ConfigEntityBase::preSave() that handles
+    // \Drupal\Core\Entity\EntityWithPluginCollectionInterface.
+    foreach ($this->getSections() as $delta => $section) {
+      $this->setSection($delta, $section);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultRegion($delta = 0) {
+    $sections = $this->getSections();
+    if (!isset($sections[$delta])) {
+      return parent::getDefaultRegion();
+    }
+
+    $section = $this->getSection($delta);
+    return $this->getLayoutDefinition($section->getLayoutId())->getDefaultRegion();
+  }
+
+  /**
+   * Gets a layout definition.
+   *
+   * @param string $layout_id
+   *   The layout ID.
+   *
+   * @return \Drupal\Core\Layout\LayoutDefinition
+   *   The layout definition.
+   */
+  protected function getLayoutDefinition($layout_id) {
+    return $this->layoutPluginManager()->getDefinition($layout_id);
+  }
+
+  /**
+   * Wraps the layout plugin manager.
+   *
+   * @return \Drupal\Core\Layout\LayoutPluginManagerInterface
+   *   The layout plugin manager.
+   */
+  protected function layoutPluginManager() {
+    return \Drupal::service('plugin.manager.core.layout');
+  }
+
+  /**
+   * Wraps the context repository service.
+   *
+   * @return \Drupal\Core\Plugin\Context\ContextRepositoryInterface
+   *   The context repository service.
+   */
+  protected function contextRepository() {
+    return \Drupal::service('context.repository');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildMultiple(array $entities) {
+    $build_list = parent::buildMultiple($entities);
+
+    foreach ($entities as $id => $entity) {
+      $sections = $this->getRuntimeSections($entity);
+      if ($sections) {
+        foreach ($build_list[$id] as $name => $build_part) {
+          $field_definition = $this->getFieldDefinition($name);
+          if ($field_definition && $field_definition->isDisplayConfigurable('view')) {
+            unset($build_list[$id][$name]);
+          }
+        }
+
+        // Bypass ::getActiveContexts() in order to use the runtime entity, not
+        // a sample entity.
+        $contexts = $this->contextRepository()->getAvailableContexts();
+        $contexts += $this->getEntityContexts($entity);
+        foreach ($sections as $delta => $section) {
+          $build_list[$id]['_layout_builder'][$delta] = $section->toRenderArray($contexts);
+        }
+      }
+    }
+
+    return $build_list;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getContexts() {
+    $contexts = [];
+    $entity_storage = $this->entityTypeManager()->getStorage($this->getTargetEntityTypeId());
+    if ($entity_storage instanceof ContentEntityStorageInterface) {
+      $entity = $entity_storage->createWithSampleValues($this->getTargetBundle());
+      $contexts = $this->getEntityContexts($entity);
+    }
+    return $contexts;
+  }
+
+  /**
+   * Gets the runtime sections for a given entity.
+   *
+   * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
+   *   The entity.
+   *
+   * @return \Drupal\layout_builder\Section[]
+   *   The sections.
+   */
+  protected function getRuntimeSections(FieldableEntityInterface $entity) {
+    if ($this->isOverridable() && !$entity->get('layout_builder__layout')->isEmpty()) {
+      return $entity->get('layout_builder__layout')->getSections();
+    }
+
+    return $this->getSections();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getStorageType() {
+    return 'defaults';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getStorageId() {
+    return $this->id();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCanonicalUrl() {
+    // Defaults do not have a canonical URL, go to the Layout Builder UI.
+    return $this->getLayoutBuilderUrl();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLayoutBuilderUrl() {
+    return $this->toUrl('layout-builder');
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplayStorage.php b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplayStorage.php
new file mode 100644
index 0000000000..7cd348da09
--- /dev/null
+++ b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplayStorage.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Drupal\layout_builder\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityStorage;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\layout_builder\Section;
+use Drupal\layout_builder\SectionComponent;
+
+/**
+ * Provides storage for entity view display entities that have layouts.
+ */
+class LayoutBuilderEntityViewDisplayStorage extends ConfigEntityStorage {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function mapToStorageRecord(EntityInterface $entity) {
+    $record = parent::mapToStorageRecord($entity);
+
+    if (!empty($record['third_party_settings']['layout_builder']['sections'])) {
+      /** @var \Drupal\layout_builder\Section[] $sections */
+      $sections = &$record['third_party_settings']['layout_builder']['sections'];
+      foreach ($sections as $section_delta => $section) {
+        $sections[$section_delta] = [
+          'layout_id' => $section->getLayoutId(),
+          'layout_settings' => $section->getLayoutSettings(),
+          'components' => $this->exportComponents($section->getComponents()),
+        ];
+      }
+    }
+    return $record;
+  }
+
+  /**
+   * Exports an array of component objects into an array suitable for storage.
+   *
+   * @param \Drupal\layout_builder\SectionComponent[] $components
+   *   The component objects.
+   *
+   * @return mixed[]
+   *   An array of components in array form.
+   */
+  protected function exportComponents(array $components) {
+    return array_map(function (SectionComponent $component) {
+      $component->toArray();
+    }, $components);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function mapFromStorageRecords(array $records) {
+    foreach ($records as $id => &$record) {
+      if (!empty($record['third_party_settings']['layout_builder']['sections'])) {
+        $sections = &$record['third_party_settings']['layout_builder']['sections'];
+        foreach ($sections as $section_delta => $section) {
+          $sections[$section_delta] = new Section(
+            $section['layout_id'],
+            $section['layout_settings'],
+            $this->importComponents($section['components'])
+          );
+        }
+      }
+    }
+    return parent::mapFromStorageRecords($records);
+  }
+
+  /**
+   * Converts the array of component data back into objects.
+   *
+   * @param mixed[] $components
+   *   An array of component data.
+   *
+   * @return \Drupal\layout_builder\SectionComponent[]
+   *   An array of component objects.
+   */
+  protected function importComponents(array $components) {
+    $import = [];
+    foreach ($components as $delta => $component) {
+      $import[$delta] = (new SectionComponent($component['uuid'], $component['region'], $component['configuration'], $component['additional']))->setWeight($component['weight']);
+    }
+    return $import;
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Entity/LayoutEntityDisplayInterface.php b/core/modules/layout_builder/src/Entity/LayoutEntityDisplayInterface.php
new file mode 100644
index 0000000000..297055401e
--- /dev/null
+++ b/core/modules/layout_builder/src/Entity/LayoutEntityDisplayInterface.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Drupal\layout_builder\Entity;
+
+use Drupal\Core\Entity\Display\EntityDisplayInterface;
+use Drupal\layout_builder\SectionStorageInterface;
+
+/**
+ * Provides an interface for entity displays that have layout.
+ *
+ * @internal
+ */
+interface LayoutEntityDisplayInterface extends EntityDisplayInterface, SectionStorageInterface {
+
+  /**
+   * Determines if the display allows custom overrides.
+   *
+   * @return bool
+   *   TRUE if custom overrides are allowed, FALSE otherwise.
+   */
+  public function isOverridable();
+
+  /**
+   * Sets the display 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/Field/LayoutSectionItemList.php b/core/modules/layout_builder/src/Field/LayoutSectionItemList.php
index c9a6b71136..d335c26478 100644
--- a/core/modules/layout_builder/src/Field/LayoutSectionItemList.php
+++ b/core/modules/layout_builder/src/Field/LayoutSectionItemList.php
@@ -3,6 +3,9 @@
 namespace Drupal\layout_builder\Field;
 
 use Drupal\Core\Field\FieldItemList;
+use Drupal\layout_builder\Context\SectionStorageEntityContextTrait;
+use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
+use Drupal\layout_builder\OverridesSectionStorageInterface;
 use Drupal\layout_builder\Section;
 use Drupal\layout_builder\SectionStorageInterface;
 
@@ -13,7 +16,9 @@
  *
  * @see \Drupal\layout_builder\Plugin\Field\FieldType\LayoutSectionItem
  */
-class LayoutSectionItemList extends FieldItemList implements SectionStorageInterface {
+class LayoutSectionItemList extends FieldItemList implements SectionStorageInterface, OverridesSectionStorageInterface {
+
+  use SectionStorageEntityContextTrait;
 
   /**
    * {@inheritdoc}
@@ -24,6 +29,7 @@ public function insertSection($delta, Section $section) {
       $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);
@@ -74,4 +80,69 @@ public function removeSection($delta) {
     return $this;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getContexts() {
+    return $this->getEntityContexts($this->getEntity());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public 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}
+   */
+  public function __wakeup() {
+    // Ensure the entity is updated with the latest value.
+    $this->getEntity()->set($this->getName(), $this->getValue());
+  }
+
 }
diff --git a/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php b/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
index 08ff317416..62858180f5 100644
--- a/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
+++ b/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
@@ -6,18 +6,18 @@
 use Drupal\Core\Block\BlockManagerInterface;
 use Drupal\Core\Block\BlockPluginInterface;
 use Drupal\Core\DependencyInjection\ClassResolverInterface;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Form\SubformState;
-use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
 use Drupal\Core\Plugin\ContextAwarePluginAssignmentTrait;
 use Drupal\Core\Plugin\ContextAwarePluginInterface;
 use Drupal\Core\Plugin\PluginFormFactoryInterface;
 use Drupal\Core\Plugin\PluginWithFormsInterface;
+use Drupal\layout_builder\Context\LayoutBuilderContextTrait;
 use Drupal\layout_builder\Controller\LayoutRebuildTrait;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Drupal\layout_builder\Section;
+use Drupal\layout_builder\SectionStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -29,6 +29,7 @@
 
   use AjaxFormHelperTrait;
   use ContextAwarePluginAssignmentTrait;
+  use LayoutBuilderContextTrait;
   use LayoutRebuildTrait;
 
   /**
@@ -38,13 +39,6 @@
    */
   protected $block;
 
-  /**
-   * The context repository.
-   *
-   * @var \Drupal\Core\Plugin\Context\ContextRepositoryInterface
-   */
-  protected $contextRepository;
-
   /**
    * The layout tempstore repository.
    *
@@ -88,19 +82,17 @@
   protected $region;
 
   /**
-   * The entity.
+   * The section storage.
    *
-   * @var \Drupal\Core\Entity\EntityInterface
+   * @var \Drupal\layout_builder\SectionStorageInterface
    */
-  protected $entity;
+  protected $sectionStorage;
 
   /**
    * Constructs a new block form.
    *
    * @param \Drupal\layout_builder\LayoutTempstoreRepositoryInterface $layout_tempstore_repository
    *   The layout tempstore repository.
-   * @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository
-   *   The context repository.
    * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
    *   The block manager.
    * @param \Drupal\Component\Uuid\UuidInterface $uuid
@@ -110,9 +102,8 @@
    * @param \Drupal\Core\Plugin\PluginFormFactoryInterface $plugin_form_manager
    *   The plugin form manager.
    */
-  public function __construct(LayoutTempstoreRepositoryInterface $layout_tempstore_repository, ContextRepositoryInterface $context_repository, BlockManagerInterface $block_manager, UuidInterface $uuid, ClassResolverInterface $class_resolver, PluginFormFactoryInterface $plugin_form_manager) {
+  public function __construct(LayoutTempstoreRepositoryInterface $layout_tempstore_repository, BlockManagerInterface $block_manager, UuidInterface $uuid, ClassResolverInterface $class_resolver, PluginFormFactoryInterface $plugin_form_manager) {
     $this->layoutTempstoreRepository = $layout_tempstore_repository;
-    $this->contextRepository = $context_repository;
     $this->blockManager = $block_manager;
     $this->uuid = $uuid;
     $this->classResolver = $class_resolver;
@@ -125,7 +116,6 @@ public function __construct(LayoutTempstoreRepositoryInterface $layout_tempstore
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('layout_builder.tempstore_repository'),
-      $container->get('context.repository'),
       $container->get('plugin.manager.block'),
       $container->get('uuid'),
       $container->get('class_resolver'),
@@ -159,8 +149,8 @@ protected function prepareBlock($block_id, array $configuration) {
    *   An associative array containing the structure of the form.
    * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the form.
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity being configured.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage being configured.
    * @param int $delta
    *   The delta of the section.
    * @param string $region
@@ -173,13 +163,13 @@ protected function prepareBlock($block_id, array $configuration) {
    * @return array
    *   The form array.
    */
-  public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $entity = NULL, $delta = NULL, $region = NULL, $plugin_id = NULL, array $configuration = []) {
-    $this->entity = $entity;
+  public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL, $delta = NULL, $region = NULL, $plugin_id = NULL, array $configuration = []) {
+    $this->sectionStorage = $section_storage;
     $this->delta = $delta;
     $this->region = $region;
     $this->block = $this->prepareBlock($plugin_id, $configuration);
 
-    $form_state->setTemporaryValue('gathered_contexts', $this->contextRepository->getAvailableContexts());
+    $form_state->setTemporaryValue('gathered_contexts', $this->getAvailableContexts($section_storage));
 
     // @todo Remove once https://www.drupal.org/node/2268787 is resolved.
     $form_state->set('block_theme', $this->config('system.theme')->get('default'));
@@ -246,20 +236,18 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
 
     $configuration = $this->block->getConfiguration();
 
-    /** @var \Drupal\layout_builder\SectionStorageInterface $field_list */
-    $field_list = $this->entity->layout_builder__layout;
-    $section = $field_list->getSection($this->delta);
+    $section = $this->sectionStorage->getSection($this->delta);
     $this->submitBlock($section, $this->region, $configuration['uuid'], $configuration);
 
-    $this->layoutTempstoreRepository->set($this->entity);
-    $form_state->setRedirectUrl($this->entity->toUrl('layout-builder'));
+    $this->layoutTempstoreRepository->set($this->sectionStorage);
+    $form_state->setRedirectUrl($this->sectionStorage->getLayoutBuilderUrl());
   }
 
   /**
    * {@inheritdoc}
    */
   protected function successfulAjaxSubmit(array $form, FormStateInterface $form_state) {
-    return $this->rebuildAndClose($this->entity);
+    return $this->rebuildAndClose($this->sectionStorage);
   }
 
   /**
diff --git a/core/modules/layout_builder/src/Form/ConfigureSectionForm.php b/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
index 0d43c3d23e..2bfcdca7c2 100644
--- a/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
+++ b/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
@@ -3,7 +3,6 @@
 namespace Drupal\layout_builder\Form;
 
 use Drupal\Core\DependencyInjection\ClassResolverInterface;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Form\SubformState;
@@ -14,6 +13,7 @@
 use Drupal\layout_builder\Controller\LayoutRebuildTrait;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Drupal\layout_builder\Section;
+use Drupal\layout_builder\SectionStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -48,11 +48,11 @@ class ConfigureSectionForm extends FormBase {
   protected $pluginFormFactory;
 
   /**
-   * The entity.
+   * The section storage.
    *
-   * @var \Drupal\Core\Entity\EntityInterface
+   * @var \Drupal\layout_builder\SectionStorageInterface
    */
-  protected $entity;
+  protected $sectionStorage;
 
   /**
    * The field delta.
@@ -105,15 +105,13 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $entity = NULL, $delta = NULL, $plugin_id = NULL) {
-    $this->entity = $entity;
+  public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL, $delta = NULL, $plugin_id = NULL) {
+    $this->sectionStorage = $section_storage;
     $this->delta = $delta;
     $this->isUpdate = is_null($plugin_id);
 
     if ($this->isUpdate) {
-      /** @var \Drupal\layout_builder\SectionStorageInterface $field_list */
-      $field_list = $this->entity->layout_builder__layout;
-      $section = $field_list->getSection($this->delta);
+      $section = $this->sectionStorage->getSection($this->delta);
     }
     else {
       $section = new Section($plugin_id);
@@ -156,24 +154,22 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
     $plugin_id = $this->layout->getPluginId();
     $configuration = $this->layout->getConfiguration();
 
-    /** @var \Drupal\layout_builder\SectionStorageInterface $field_list */
-    $field_list = $this->entity->layout_builder__layout;
     if ($this->isUpdate) {
-      $field_list->getSection($this->delta)->setLayoutSettings($configuration);
+      $this->sectionStorage->getSection($this->delta)->setLayoutSettings($configuration);
     }
     else {
-      $field_list->insertSection($this->delta, new Section($plugin_id, $configuration));
+      $this->sectionStorage->insertSection($this->delta, new Section($plugin_id, $configuration));
     }
 
-    $this->layoutTempstoreRepository->set($this->entity);
-    $form_state->setRedirectUrl($this->entity->toUrl('layout-builder'));
+    $this->layoutTempstoreRepository->set($this->sectionStorage);
+    $form_state->setRedirectUrl($this->sectionStorage->getLayoutBuilderUrl());
   }
 
   /**
    * {@inheritdoc}
    */
   protected function successfulAjaxSubmit(array $form, FormStateInterface $form_state) {
-    return $this->rebuildAndClose($this->entity);
+    return $this->rebuildAndClose($this->sectionStorage);
   }
 
   /**
diff --git a/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php b/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
index 8bee062d4e..511a11968e 100644
--- a/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
+++ b/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
@@ -3,11 +3,11 @@
 namespace Drupal\layout_builder\Form;
 
 use Drupal\Core\DependencyInjection\ClassResolverInterface;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\layout_builder\Controller\LayoutRebuildTrait;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
+use Drupal\layout_builder\SectionStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -28,11 +28,11 @@
   protected $layoutTempstoreRepository;
 
   /**
-   * The entity.
+   * The section storage.
    *
-   * @var \Drupal\Core\Entity\EntityInterface
+   * @var \Drupal\layout_builder\SectionStorageInterface
    */
-  protected $entity;
+  protected $sectionStorage;
 
   /**
    * The field delta.
@@ -68,14 +68,14 @@ public static function create(ContainerInterface $container) {
    * {@inheritdoc}
    */
   public function getCancelUrl() {
-    return $this->entity->toUrl('layout-builder', ['query' => ['layout_is_rebuilding' => TRUE]]);
+    return $this->sectionStorage->getLayoutBuilderUrl()->setOption('query', ['layout_is_rebuilding' => TRUE]);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $entity = NULL, $delta = NULL) {
-    $this->entity = $entity;
+  public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL, $delta = NULL) {
+    $this->sectionStorage = $section_storage;
     $this->delta = $delta;
 
     $form = parent::buildForm($form, $form_state);
@@ -92,9 +92,9 @@ public function buildForm(array $form, FormStateInterface $form_state, EntityInt
    * {@inheritdoc}
    */
   public function submitForm(array &$form, FormStateInterface $form_state) {
-    $this->handleEntity($this->entity, $form_state);
+    $this->handleSectionStorage($this->sectionStorage, $form_state);
 
-    $this->layoutTempstoreRepository->set($this->entity);
+    $this->layoutTempstoreRepository->set($this->sectionStorage);
 
     $form_state->setRedirectUrl($this->getCancelUrl());
   }
@@ -103,17 +103,17 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   protected function successfulAjaxSubmit(array $form, FormStateInterface $form_state) {
-    return $this->rebuildAndClose($this->entity);
+    return $this->rebuildAndClose($this->sectionStorage);
   }
 
   /**
-   * Performs any actions on the layout entity before saving.
+   * Performs any actions on the section storage before saving.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
    * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the form.
    */
-  abstract protected function handleEntity(EntityInterface $entity, FormStateInterface $form_state);
+  abstract protected function handleSectionStorage(SectionStorageInterface $section_storage, FormStateInterface $form_state);
 
 }
diff --git a/core/modules/layout_builder/src/Form/RemoveBlockForm.php b/core/modules/layout_builder/src/Form/RemoveBlockForm.php
index 9c7eb2084d..105047d161 100644
--- a/core/modules/layout_builder/src/Form/RemoveBlockForm.php
+++ b/core/modules/layout_builder/src/Form/RemoveBlockForm.php
@@ -2,8 +2,8 @@
 
 namespace Drupal\layout_builder\Form;
 
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\layout_builder\SectionStorageInterface;
 
 /**
  * Provides a form to confirm the removal of a block.
@@ -50,19 +50,17 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $entity = NULL, $delta = NULL, $region = NULL, $uuid = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL, $delta = NULL, $region = NULL, $uuid = NULL) {
     $this->region = $region;
     $this->uuid = $uuid;
-    return parent::buildForm($form, $form_state, $entity, $delta);
+    return parent::buildForm($form, $form_state, $section_storage, $delta);
   }
 
   /**
    * {@inheritdoc}
    */
-  protected function handleEntity(EntityInterface $entity, FormStateInterface $form_state) {
-    /** @var \Drupal\layout_builder\SectionStorageInterface $field_list */
-    $field_list = $this->entity->layout_builder__layout;
-    $field_list->getSection($this->delta)->removeComponent($this->uuid);
+  protected function handleSectionStorage(SectionStorageInterface $section_storage, FormStateInterface $form_state) {
+    $section_storage->getSection($this->delta)->removeComponent($this->uuid);
   }
 
 }
diff --git a/core/modules/layout_builder/src/Form/RemoveSectionForm.php b/core/modules/layout_builder/src/Form/RemoveSectionForm.php
index e44edd6947..aa58a3b2ed 100644
--- a/core/modules/layout_builder/src/Form/RemoveSectionForm.php
+++ b/core/modules/layout_builder/src/Form/RemoveSectionForm.php
@@ -2,8 +2,8 @@
 
 namespace Drupal\layout_builder\Form;
 
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\layout_builder\SectionStorageInterface;
 
 /**
  * Provides a form to confirm the removal of a section.
@@ -36,8 +36,8 @@ public function getConfirmText() {
   /**
    * {@inheritdoc}
    */
-  protected function handleEntity(EntityInterface $entity, FormStateInterface $form_state) {
-    $entity->layout_builder__layout->removeItem($this->delta);
+  protected function handleSectionStorage(SectionStorageInterface $section_storage, FormStateInterface $form_state) {
+    $section_storage->removeSection($this->delta);
   }
 
 }
diff --git a/core/modules/layout_builder/src/Form/UpdateBlockForm.php b/core/modules/layout_builder/src/Form/UpdateBlockForm.php
index 443deedaeb..afca0d25c9 100644
--- a/core/modules/layout_builder/src/Form/UpdateBlockForm.php
+++ b/core/modules/layout_builder/src/Form/UpdateBlockForm.php
@@ -2,9 +2,10 @@
 
 namespace Drupal\layout_builder\Form;
 
-use Drupal\Core\Entity\EntityInterface;
+use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\layout_builder\Section;
+use Drupal\layout_builder\SectionStorageInterface;
 
 /**
  * Provides a form to update a block.
@@ -27,8 +28,8 @@ public function getFormId() {
    *   An associative array containing the structure of the form.
    * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the form.
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity being configured.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage being configured.
    * @param int $delta
    *   The delta of the section.
    * @param string $region
@@ -41,12 +42,13 @@ public function getFormId() {
    * @return array
    *   The form array.
    */
-  public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $entity = NULL, $delta = NULL, $region = NULL, $uuid = NULL, array $configuration = []) {
-    /** @var \Drupal\layout_builder\SectionStorageInterface $field_list */
-    $field_list = $entity->layout_builder__layout;
-    $plugin = $field_list->getSection($delta)->getComponent($uuid)->getPlugin();
+  public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL, $delta = NULL, $region = NULL, $uuid = NULL, array $configuration = []) {
+    $plugin = $section_storage->getSection($delta)->getComponent($uuid)->getPlugin();
+    if ($plugin instanceof ConfigurablePluginInterface) {
+      $configuration = $plugin->getConfiguration();
+    }
 
-    return parent::buildForm($form, $form_state, $entity, $delta, $region, $plugin->getPluginId(), $plugin->getConfiguration());
+    return parent::buildForm($form, $form_state, $section_storage, $delta, $region, $plugin->getPluginId(), $configuration);
   }
 
   /**
diff --git a/core/modules/layout_builder/src/LayoutTempstoreRepository.php b/core/modules/layout_builder/src/LayoutTempstoreRepository.php
index 87baa1331c..5e1a18d36a 100644
--- a/core/modules/layout_builder/src/LayoutTempstoreRepository.php
+++ b/core/modules/layout_builder/src/LayoutTempstoreRepository.php
@@ -2,9 +2,6 @@
 
 namespace Drupal\layout_builder;
 
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Entity\RevisionableInterface;
 use Drupal\user\SharedTempStoreFactory;
 
 /**
@@ -21,97 +18,60 @@ class LayoutTempstoreRepository implements LayoutTempstoreRepositoryInterface {
    */
   protected $tempStoreFactory;
 
-  /**
-   * The entity type manager.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected $entityTypeManager;
-
   /**
    * LayoutTempstoreRepository constructor.
    *
    * @param \Drupal\user\SharedTempStoreFactory $temp_store_factory
    *   The shared 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) {
+  public function __construct(SharedTempStoreFactory $temp_store_factory) {
     $this->tempStoreFactory = $temp_store_factory;
-    $this->entityTypeManager = $entity_type_manager;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function get(EntityInterface $entity) {
-    $id = $this->generateTempstoreId($entity);
-    $tempstore = $this->getTempstore($entity)->get($id);
-    if (!empty($tempstore['entity'])) {
-      $entity_type_id = $entity->getEntityTypeId();
-      $entity = $tempstore['entity'];
+  public function get(SectionStorageInterface $section_storage) {
+    $id = $section_storage->getStorageId();
+    $tempstore = $this->getTempstore($section_storage)->get($id);
+    if (!empty($tempstore['section_storage'])) {
+      $storage_type = $section_storage->getStorageType();
+      $section_storage = $tempstore['section_storage'];
 
-      if (!($entity instanceof EntityInterface)) {
-        throw new \UnexpectedValueException(sprintf('The entry with entity type "%s" and ID "%s" is not a valid entity', $entity_type_id, $id));
+      if (!($section_storage instanceof SectionStorageInterface)) {
+        throw new \UnexpectedValueException(sprintf('The entry with storage type "%s" and ID "%s" is invalid', $storage_type, $id));
       }
     }
-    return $entity;
+    return $section_storage;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function getFromId($entity_type_id, $entity_id) {
-    $entity = $this->entityTypeManager->getStorage($entity_type_id)->loadRevision($entity_id);
-    return $this->get($entity);
+  public function set(SectionStorageInterface $section_storage) {
+    $id = $section_storage->getStorageId();
+    $this->getTempstore($section_storage)->set($id, ['section_storage' => $section_storage]);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function set(EntityInterface $entity) {
-    $id = $this->generateTempstoreId($entity);
-    $this->getTempstore($entity)->set($id, ['entity' => $entity]);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function delete(EntityInterface $entity) {
-    if ($this->get($entity)) {
-      $id = $this->generateTempstoreId($entity);
-      $this->getTempstore($entity)->delete($id);
-    }
-  }
-
-  /**
-   * Generates an ID for putting an entity in tempstore.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity being stored.
-   *
-   * @return string
-   *   The tempstore ID.
-   */
-  protected function generateTempstoreId(EntityInterface $entity) {
-    $id = "{$entity->id()}.{$entity->language()->getId()}";
-    if ($entity instanceof RevisionableInterface) {
-      $id .= '.' . $entity->getRevisionId();
-    }
-    return $id;
+  public function delete(SectionStorageInterface $section_storage) {
+    $id = $section_storage->getStorageId();
+    $this->getTempstore($section_storage)->delete($id);
   }
 
   /**
    * Gets the shared tempstore.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity being stored.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage.
    *
    * @return \Drupal\user\SharedTempStore
    *   The tempstore.
    */
-  protected function getTempstore(EntityInterface $entity) {
-    $collection = $entity->getEntityTypeId() . '.layout_builder__layout';
+  protected function getTempstore(SectionStorageInterface $section_storage) {
+    $collection = 'layout_builder.' . $section_storage->getStorageType();
     return $this->tempStoreFactory->get($collection);
   }
 
diff --git a/core/modules/layout_builder/src/LayoutTempstoreRepositoryInterface.php b/core/modules/layout_builder/src/LayoutTempstoreRepositoryInterface.php
index ffce1c3008..4972a47f6f 100644
--- a/core/modules/layout_builder/src/LayoutTempstoreRepositoryInterface.php
+++ b/core/modules/layout_builder/src/LayoutTempstoreRepositoryInterface.php
@@ -2,8 +2,6 @@
 
 namespace Drupal\layout_builder;
 
-use Drupal\Core\Entity\EntityInterface;
-
 /**
  * Provides an interface for loading layouts from tempstore.
  *
@@ -15,51 +13,34 @@
 interface LayoutTempstoreRepositoryInterface {
 
   /**
-   * Gets the tempstore version of an entity, if it exists.
+   * Gets the tempstore version of a section storage, if it exists.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity to check for in tempstore.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage to check for in tempstore.
    *
-   * @return \Drupal\Core\Entity\EntityInterface
-   *   Either the version of this entity from tempstore, or the passed entity if
-   *   none exists.
+   * @return \Drupal\layout_builder\SectionStorageInterface
+   *   Either the version of this section storage from tempstore, or the passed
+   *   section storage if none exists.
    *
    * @throw \UnexpectedValueException
-   *   Thrown if a value exists, but is not an entity.
+   *   Thrown if a value exists, but is not a section storage.
    */
-  public function get(EntityInterface $entity);
+  public function get(SectionStorageInterface $section_storage);
 
   /**
-   * Loads an entity from tempstore given the entity ID.
+   * Stores this section storage in tempstore.
    *
-   * @param string $entity_type_id
-   *   The entity type ID.
-   * @param string $entity_id
-   *   The entity ID (or revision ID).
-   *
-   * @return \Drupal\Core\Entity\EntityInterface
-   *   Either the version of this entity from tempstore, or the entity from
-   *   storage if none exists.
-   *
-   * @throw \UnexpectedValueException
-   *   Thrown if a value exists, but is not an entity.
-   */
-  public function getFromId($entity_type_id, $entity_id);
-
-  /**
-   * Stores this entity in tempstore.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity to set in tempstore.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage to set in tempstore.
    */
-  public function set(EntityInterface $entity);
+  public function set(SectionStorageInterface $section_storage);
 
   /**
-   * Removes the tempstore version of an entity.
+   * Removes the tempstore version of a section storage.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity to remove from tempstore.
+   * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
+   *   The section storage to remove from tempstore.
    */
-  public function delete(EntityInterface $entity);
+  public function delete(SectionStorageInterface $section_storage);
 
 }
diff --git a/core/modules/layout_builder/src/OverridesSectionStorageInterface.php b/core/modules/layout_builder/src/OverridesSectionStorageInterface.php
new file mode 100644
index 0000000000..40bb73153c
--- /dev/null
+++ b/core/modules/layout_builder/src/OverridesSectionStorageInterface.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Drupal\layout_builder;
+
+/**
+ * Defines an interface for an object that stores layout sections for 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.
+ */
+interface OverridesSectionStorageInterface {
+
+  /**
+   * Returns the corresponding defaults section storage for this override.
+   *
+   * @return \Drupal\layout_builder\SectionStorageInterface
+   *   The defaults section storage.
+   */
+  public function getDefaultSectionStorage();
+
+}
diff --git a/core/modules/layout_builder/src/Plugin/Derivative/LayoutBuilderLocalTaskDeriver.php b/core/modules/layout_builder/src/Plugin/Derivative/LayoutBuilderLocalTaskDeriver.php
index 7054dd3605..1abc785838 100644
--- a/core/modules/layout_builder/src/Plugin/Derivative/LayoutBuilderLocalTaskDeriver.php
+++ b/core/modules/layout_builder/src/Plugin/Derivative/LayoutBuilderLocalTaskDeriver.php
@@ -7,7 +7,6 @@
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
-use Drupal\layout_builder\Plugin\Menu\LayoutBuilderLocalTask;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -49,33 +48,52 @@ public static function create(ContainerInterface $container, $base_plugin_id) {
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    foreach (array_keys($this->getEntityTypes()) as $entity_type_id) {
+    foreach ($this->getEntityTypes() as $entity_type_id => $entity_type) {
       $this->derivatives["entity.$entity_type_id.layout_builder"] = $base_plugin_definition + [
         'route_name' => "entity.$entity_type_id.layout_builder",
         'weight' => 15,
         'title' => $this->t('Layout'),
         'base_route' => "entity.$entity_type_id.canonical",
         'entity_type_id' => $entity_type_id,
-        'class' => LayoutBuilderLocalTask::class,
         'cache_contexts' => ['layout_builder_is_active:' . $entity_type_id],
       ];
-      $this->derivatives["entity.$entity_type_id.save_layout"] = $base_plugin_definition + [
-        'route_name' => "entity.$entity_type_id.save_layout",
+      $this->derivatives["entity.$entity_type_id.layout_builder_save"] = $base_plugin_definition + [
+        'route_name' => "entity.$entity_type_id.layout_builder_save",
         'title' => $this->t('Save Layout'),
         'parent_id' => "layout_builder_ui:entity.$entity_type_id.layout_builder",
         'entity_type_id' => $entity_type_id,
-        'class' => LayoutBuilderLocalTask::class,
         'cache_contexts' => ['layout_builder_is_active:' . $entity_type_id],
       ];
-      $this->derivatives["entity.$entity_type_id.cancel_layout"] = $base_plugin_definition + [
-        'route_name' => "entity.$entity_type_id.cancel_layout",
+      $this->derivatives["entity.$entity_type_id.layout_builder_cancel"] = $base_plugin_definition + [
+        'route_name' => "entity.$entity_type_id.layout_builder_cancel",
         'title' => $this->t('Cancel Layout'),
         'parent_id' => "layout_builder_ui:entity.$entity_type_id.layout_builder",
         'entity_type_id' => $entity_type_id,
-        'class' => LayoutBuilderLocalTask::class,
         'weight' => 5,
         'cache_contexts' => ['layout_builder_is_active:' . $entity_type_id],
       ];
+      if ($route_name = $entity_type->get('field_ui_base_route')) {
+        $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",
+          'weight' => 4,
+          'title' => $this->t('Manage layout'),
+          'base_route' => $route_name,
+          'entity_type_id' => $entity_type_id,
+        ];
+        $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",
+          '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,
+        ];
+        $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",
+          '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,
+        ];
+      }
     }
 
     return $this->derivatives;
diff --git a/core/modules/layout_builder/src/Plugin/Field/FieldFormatter/LayoutSectionFormatter.php b/core/modules/layout_builder/src/Plugin/Field/FieldFormatter/LayoutSectionFormatter.php
deleted file mode 100644
index c579b3e4fc..0000000000
--- a/core/modules/layout_builder/src/Plugin/Field/FieldFormatter/LayoutSectionFormatter.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-
-namespace Drupal\layout_builder\Plugin\Field\FieldFormatter;
-
-use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\Core\Field\FormatterBase;
-
-/**
- * Plugin implementation of the 'layout_section' formatter.
- *
- * @internal
- *
- * @FieldFormatter(
- *   id = "layout_section",
- *   label = @Translation("Layout Section"),
- *   field_types = {
- *     "layout_section"
- *   }
- * )
- */
-class LayoutSectionFormatter extends FormatterBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function viewElements(FieldItemListInterface $items, $langcode) {
-    $elements = [];
-
-    /** @var \Drupal\layout_builder\SectionStorageInterface $items */
-    foreach ($items->getSections() as $delta => $section) {
-      $elements[$delta] = $section->toRenderArray();
-    }
-
-    return $elements;
-  }
-
-}
diff --git a/core/modules/layout_builder/src/Plugin/Menu/LayoutBuilderLocalTask.php b/core/modules/layout_builder/src/Plugin/Menu/LayoutBuilderLocalTask.php
deleted file mode 100644
index 0098e35313..0000000000
--- a/core/modules/layout_builder/src/Plugin/Menu/LayoutBuilderLocalTask.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-
-namespace Drupal\layout_builder\Plugin\Menu;
-
-use Drupal\Core\Menu\LocalTaskDefault;
-use Drupal\Core\Routing\RouteMatchInterface;
-
-/**
- * Provides route parameters needed to link to layout related tabs.
- *
- * @internal
- */
-class LayoutBuilderLocalTask extends LocalTaskDefault {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getRouteParameters(RouteMatchInterface $route_match) {
-    $parameters = parent::getRouteParameters($route_match);
-
-    // @todo Revisit this code once https://www.drupal.org/node/2912363 is in.
-    $parameters['entity'] = $route_match->getParameter('entity');
-    return $parameters;
-  }
-
-}
diff --git a/core/modules/layout_builder/src/Routing/LayoutBuilderRouteEnhancer.php b/core/modules/layout_builder/src/Routing/LayoutBuilderRouteEnhancer.php
index 66dbbbadc9..65d25423c9 100644
--- a/core/modules/layout_builder/src/Routing/LayoutBuilderRouteEnhancer.php
+++ b/core/modules/layout_builder/src/Routing/LayoutBuilderRouteEnhancer.php
@@ -5,45 +5,22 @@
 use Drupal\Core\Routing\EnhancerInterface;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\Routing\Route;
 
 /**
- * Enhances routes to ensure the entity is available with a generic name.
+ * Converts the query parameter for layout rebuild status to a route default.
  *
  * @internal
  */
 class LayoutBuilderRouteEnhancer implements EnhancerInterface {
 
-  /**
-   * Returns whether the enhancer runs on the current route.
-   *
-   * @param \Symfony\Component\Routing\Route $route
-   *   The current route.
-   *
-   * @return bool
-   *   TRUE if this enhancer applies to this route.
-   */
-  protected function applies(Route $route) {
-    return $route->getOption('_layout_builder') && $route->getDefault('entity_type_id');
-  }
-
   /**
    * {@inheritdoc}
    */
   public function enhance(array $defaults, Request $request) {
     $route = $defaults[RouteObjectInterface::ROUTE_OBJECT];
-    if (!$this->applies($route)) {
-      return $defaults;
+    if ($route->hasOption('_layout_builder')) {
+      $defaults['is_rebuilding'] = (bool) $request->query->get('layout_is_rebuilding', FALSE);
     }
-
-    $defaults['is_rebuilding'] = (bool) $request->query->get('layout_is_rebuilding', FALSE);
-
-    if (!isset($defaults[$defaults['entity_type_id']])) {
-      throw new \RuntimeException(sprintf('Failed to find the "%s" entity in route named %s', $defaults['entity_type_id'], $defaults[RouteObjectInterface::ROUTE_NAME]));
-    }
-
-    // Copy the entity by reference so that any changes are reflected.
-    $defaults['entity'] = &$defaults[$defaults['entity_type_id']];
     return $defaults;
   }
 
diff --git a/core/modules/layout_builder/src/Routing/LayoutBuilderRoutes.php b/core/modules/layout_builder/src/Routing/LayoutBuilderRoutes.php
index b8221dfd79..85640c9f21 100644
--- a/core/modules/layout_builder/src/Routing/LayoutBuilderRoutes.php
+++ b/core/modules/layout_builder/src/Routing/LayoutBuilderRoutes.php
@@ -5,6 +5,9 @@
 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 Symfony\Component\EventDispatcher\EventSubscriberInterface;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -12,7 +15,7 @@
  *
  * @internal
  */
-class LayoutBuilderRoutes {
+class LayoutBuilderRoutes implements EventSubscriberInterface {
 
   /**
    * The entity type manager.
@@ -51,80 +54,124 @@ public function getRoutes() {
     $routes = [];
 
     foreach ($this->getEntityTypes() as $entity_type_id => $entity_type) {
-      $integer_id = $this->hasIntegerId($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');
-      $route = (new Route($template))
-        ->setDefaults([
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::layout',
-          '_title_callback' => '\Drupal\layout_builder\Controller\LayoutBuilderController::title',
-          'entity' => NULL,
-          'entity_type_id' => $entity_type_id,
-          'is_rebuilding' => FALSE,
-        ])
-        ->addRequirements([
-          '_has_layout_section' => 'true',
-        ])
-        ->addOptions([
-          '_layout_builder' => TRUE,
-          'parameters' => [
-            $entity_type_id => [
-              'type' => 'entity:{entity_type_id}',
-              'layout_builder_tempstore' => TRUE,
-            ],
-          ],
-        ]);
-      if ($integer_id) {
-        $route->setRequirement($entity_type_id, '\d+');
-      }
-      $routes["entity.$entity_type_id.layout_builder"] = $route;
+      $routes += $this->buildRoute('overrides', 'entity.' . $entity_type_id, $template, $defaults, $requirements, $options);
+    }
+    return $routes;
+  }
 
-      $route = (new Route("$template/save"))
-        ->setDefaults([
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout',
-          'entity' => NULL,
-          'entity_type_id' => $entity_type_id,
-        ])
-        ->addRequirements([
-          '_has_layout_section' => 'true',
-        ])
-        ->addOptions([
-          '_layout_builder' => TRUE,
-          'parameters' => [
-            $entity_type_id => [
-              'type' => 'entity:{entity_type_id}',
-              'layout_builder_tempstore' => TRUE,
-            ],
-          ],
-        ]);
-      if ($integer_id) {
-        $route->setRequirement($entity_type_id, '\d+');
-      }
-      $routes["entity.$entity_type_id.save_layout"] = $route;
+  /**
+   * Alters existing routes for a specific collection.
+   *
+   * @param \Drupal\Core\Routing\RouteBuildEvent $event
+   *   The route build event.
+   */
+  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';
+
+        $defaults = [];
+        $defaults['entity_type_id'] = $entity_type_id;
+        $defaults['view_mode_name'] = 'default';
+        // 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['parameters']['section_storage']['layout_builder_tempstore'] = TRUE;
 
-      $route = (new Route("$template/cancel"))
-        ->setDefaults([
-          '_controller' => '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout',
-          'entity' => NULL,
-          'entity_type_id' => $entity_type_id,
-        ])
-        ->addRequirements([
-          '_has_layout_section' => 'true',
-        ])
-        ->addOptions([
-          '_layout_builder' => TRUE,
-          'parameters' => [
-            $entity_type_id => [
-              'type' => 'entity:{entity_type_id}',
-              'layout_builder_tempstore' => TRUE,
-            ],
-          ],
-        ]);
-      if ($integer_id) {
-        $route->setRequirement($entity_type_id, '\d+');
+        $routes = $this->buildRoute('defaults', 'entity.entity_view_display.' . $entity_type_id, $path, $defaults, $requirements, $options);
+        foreach ($routes as $name => $route) {
+          $collection->add($name, $route);
+        }
       }
-      $routes["entity.$entity_type_id.cancel_layout"] = $route;
     }
+  }
+
+  /**
+   * Builds the layout routes for the given values.
+   *
+   * @param string $type
+   *   The section storage type.
+   * @param string $route_name_prefix
+   *   The prefix to use for the route name.
+   * @param string $path
+   *   The path patten for the routes.
+   * @param array $defaults
+   *   An array of default parameter values.
+   * @param array $requirements
+   *   An array of requirements for parameters.
+   * @param array $options
+   *   An array of options.
+   *
+   * @return \Symfony\Component\Routing\Route[]
+   *   An array of route objects.
+   */
+  protected function buildRoute($type, $route_name_prefix, $path, array $defaults, array $requirements, array $options) {
+    $routes = [];
+
+    $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;
+
+    $main_defaults = $defaults;
+    $main_defaults['is_rebuilding'] = FALSE;
+    $main_defaults['_controller'] = '\Drupal\layout_builder\Controller\LayoutBuilderController::layout';
+    $main_defaults['_title_callback'] = '\Drupal\layout_builder\Controller\LayoutBuilderController::title';
+    $route = (new Route($path))
+      ->setDefaults($main_defaults)
+      ->setRequirements($requirements)
+      ->setOptions($options);
+    $routes["{$route_name_prefix}.layout_builder"] = $route;
+
+    $save_defaults = $defaults;
+    $save_defaults['_controller'] = '\Drupal\layout_builder\Controller\LayoutBuilderController::saveLayout';
+    $route = (new Route("$path/save"))
+      ->setDefaults($save_defaults)
+      ->setRequirements($requirements)
+      ->setOptions($options);
+    $routes["{$route_name_prefix}.layout_builder_save"] = $route;
+
+    $cancel_defaults = $defaults;
+    $cancel_defaults['_controller'] = '\Drupal\layout_builder\Controller\LayoutBuilderController::cancelLayout';
+    $route = (new Route("$path/cancel"))
+      ->setDefaults($cancel_defaults)
+      ->setRequirements($requirements)
+      ->setOptions($options);
+    $routes["{$route_name_prefix}.layout_builder_cancel"] = $route;
+
     return $routes;
   }
 
@@ -154,4 +201,13 @@ protected function getEntityTypes() {
     });
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    // Run after \Drupal\field_ui\Routing\RouteSubscriber.
+    $events[RoutingEvents::ALTER] = ['onAlterRoutes', -110];
+    return $events;
+  }
+
 }
diff --git a/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php b/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php
index a1d5fc9140..228a786764 100644
--- a/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php
+++ b/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php
@@ -2,18 +2,17 @@
 
 namespace Drupal\layout_builder\Routing;
 
-use Drupal\Core\Entity\EntityManagerInterface;
-use Drupal\Core\ParamConverter\EntityConverter;
+use Drupal\Core\DependencyInjection\ClassResolverInterface;
 use Drupal\Core\ParamConverter\ParamConverterInterface;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Symfony\Component\Routing\Route;
 
 /**
- * Loads the entity from the layout tempstore.
+ * Loads the section storage from the layout tempstore.
  *
  * @internal
  */
-class LayoutTempstoreParamConverter extends EntityConverter implements ParamConverterInterface {
+class LayoutTempstoreParamConverter implements ParamConverterInterface {
 
   /**
    * The layout tempstore repository.
@@ -22,25 +21,61 @@ class LayoutTempstoreParamConverter extends EntityConverter implements ParamConv
    */
   protected $layoutTempstoreRepository;
 
+  /**
+   * The class resolver.
+   *
+   * @var \Drupal\Core\DependencyInjection\ClassResolverInterface
+   */
+  protected $classResolver;
+
   /**
    * Constructs a new LayoutTempstoreParamConverter.
    *
-   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
-   *   The entity manager.
    * @param \Drupal\layout_builder\LayoutTempstoreRepositoryInterface $layout_tempstore_repository
    *   The layout tempstore repository.
+   * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
+   *   The class resolver.
    */
-  public function __construct(EntityManagerInterface $entity_manager, LayoutTempstoreRepositoryInterface $layout_tempstore_repository) {
-    parent::__construct($entity_manager);
+  public function __construct(LayoutTempstoreRepositoryInterface $layout_tempstore_repository, ClassResolverInterface $class_resolver) {
     $this->layoutTempstoreRepository = $layout_tempstore_repository;
+    $this->classResolver = $class_resolver;
   }
 
   /**
    * {@inheritdoc}
    */
   public function convert($value, $definition, $name, array $defaults) {
-    if ($entity = parent::convert($value, $definition, $name, $defaults)) {
-      return $this->layoutTempstoreRepository->get($entity);
+    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;
+      }
     }
   }
 
diff --git a/core/modules/layout_builder/src/Routing/SectionStorageDefaultsParamConverter.php b/core/modules/layout_builder/src/Routing/SectionStorageDefaultsParamConverter.php
new file mode 100644
index 0000000000..3937389172
--- /dev/null
+++ b/core/modules/layout_builder/src/Routing/SectionStorageDefaultsParamConverter.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Drupal\layout_builder\Routing;
+
+use Drupal\Core\ParamConverter\EntityConverter;
+
+/**
+ * Provides a param converter for defaults-based section storage.
+ */
+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'];
+    }
+    return parent::convert($value, $definition, $name, $defaults);
+  }
+
+  /**
+   * {@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
new file mode 100644
index 0000000000..8d8ae58059
--- /dev/null
+++ b/core/modules/layout_builder/src/Routing/SectionStorageOverridesParamConverter.php
@@ -0,0 +1,70 @@
+<?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
new file mode 100644
index 0000000000..955b673513
--- /dev/null
+++ b/core/modules/layout_builder/src/Routing/SectionStorageParamConverterInterface.php
@@ -0,0 +1,34 @@
+<?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/Section.php b/core/modules/layout_builder/src/Section.php
index 55204ddc9e..1640a300d1 100644
--- a/core/modules/layout_builder/src/Section.php
+++ b/core/modules/layout_builder/src/Section.php
@@ -66,18 +66,27 @@ public function __construct($layout_id, array $layout_settings = [], array $comp
   /**
    * Returns the renderable array for this section.
    *
+   * @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
+   *   An array of available contexts.
+   *
    * @return array
    *   A renderable array representing the content of the section.
    */
-  public function toRenderArray() {
-    $regions = [];
+  public function toRenderArray(array $contexts = []) {
+    $layout = $this->getLayout();
+
+    // @todo Add the regions to the $build in the correct order. This is done
+    //   for parity with \Drupal\field_layout\FieldLayoutBuilder::buildView(),
+    //   which incorrectly adds all regions to the build.
+    $regions = array_fill_keys($layout->getPluginDefinition()->getRegionNames(), []);
+
     foreach ($this->getComponents() as $component) {
-      if ($output = $component->toRenderArray()) {
+      if ($output = $component->toRenderArray($contexts)) {
         $regions[$component->getRegion()][$component->getUuid()] = $output;
       }
     }
 
-    return $this->getLayout()->build($regions);
+    return $layout->build($regions);
   }
 
   /**
diff --git a/core/modules/layout_builder/src/SectionComponent.php b/core/modules/layout_builder/src/SectionComponent.php
index caad0a2b61..e842a165fc 100644
--- a/core/modules/layout_builder/src/SectionComponent.php
+++ b/core/modules/layout_builder/src/SectionComponent.php
@@ -88,13 +88,16 @@ public function __construct($uuid, $region, array $configuration = [], array $ad
   /**
    * Returns the renderable array for this component.
    *
+   * @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
+   *   An array of available contexts.
+   *
    * @return array
    *   A renderable array representing the content of the component.
    */
-  public function toRenderArray() {
+  public function toRenderArray(array $contexts = []) {
     $output = [];
 
-    $plugin = $this->getPlugin();
+    $plugin = $this->getPlugin($contexts);
     // @todo Figure out the best way to unify fields and blocks and components
     //   in https://www.drupal.org/node/1875974.
     if ($plugin instanceof BlockPluginInterface) {
@@ -259,13 +262,15 @@ public function getUuid() {
   /**
    * Gets the plugin for this component.
    *
+   * @param \Drupal\Core\Plugin\Context\ContextInterface[] $contexts
+   *   An array of contexts to set on the plugin.
+   *
    * @return \Drupal\Component\Plugin\PluginInspectionInterface
    *   The plugin.
    */
-  public function getPlugin() {
+  public function getPlugin(array $contexts = []) {
     $plugin = $this->pluginManager()->createInstance($this->getPluginId(), $this->getConfiguration());
     if ($plugin instanceof ContextAwarePluginInterface) {
-      $contexts = $this->contextRepository()->getRuntimeContexts(array_values($plugin->getContextMapping()));
       $this->contextHandler()->applyContextMapping($plugin, $contexts);
     }
     return $plugin;
@@ -281,16 +286,6 @@ protected function pluginManager() {
     return \Drupal::service('plugin.manager.block');
   }
 
-  /**
-   * Wraps the context repository.
-   *
-   * @return \Drupal\Core\Plugin\Context\ContextRepositoryInterface
-   *   The context repository.
-   */
-  protected function contextRepository() {
-    return \Drupal::service('context.repository');
-  }
-
   /**
    * Wraps the context handler.
    *
@@ -311,4 +306,22 @@ protected function currentUser() {
     return \Drupal::currentUser();
   }
 
+  /**
+   * Returns an array representation of the section component.
+   *
+   * This is intended for use by a storage mechanism for section components.
+   *
+   * @return array
+   *   An array representation of the section component.
+   */
+  public function toArray() {
+    return [
+      'uuid' => $this->getUuid(),
+      'region' => $this->getRegion(),
+      'configuration' => $this->getConfiguration(),
+      'additional' => $this->additional,
+      'weight' => $this->getWeight(),
+    ];
+  }
+
 }
diff --git a/core/modules/layout_builder/src/SectionStorageInterface.php b/core/modules/layout_builder/src/SectionStorageInterface.php
index c4da487eba..13217d82b4 100644
--- a/core/modules/layout_builder/src/SectionStorageInterface.php
+++ b/core/modules/layout_builder/src/SectionStorageInterface.php
@@ -68,4 +68,63 @@ public function insertSection($delta, Section $section);
    */
   public function removeSection($delta);
 
+  /**
+   * Provides any available contexts for the object using the sections.
+   *
+   * @return \Drupal\Core\Plugin\Context\ContextInterface[]
+   *   The array of context objects.
+   */
+  public function getContexts();
+
+  /**
+   * Returns an identifier for this storage.
+   *
+   * @return string
+   *   The unique identifier for this storage.
+   */
+  public function getStorageId();
+
+  /**
+   * Returns the type of this storage.
+   *
+   * Used in conjunction with the storage ID.
+   *
+   * @return string
+   *   The type of storage.
+   */
+  public function getStorageType();
+
+  /**
+   * Gets the label for the object using the sections.
+   *
+   * @return string
+   *   The label, or NULL if there is no label defined.
+   */
+  public function label();
+
+  /**
+   * Saves the sections.
+   *
+   * @return int
+   *   SAVED_NEW or SAVED_UPDATED is returned depending on the operation
+   *   performed.
+   */
+  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 90ad29886a..d2842d7fea 100644
--- a/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php
+++ b/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php
@@ -2,8 +2,8 @@
 
 namespace Drupal\Tests\layout_builder\Functional;
 
-use Drupal\Core\Entity\Entity\EntityViewDisplay;
 use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
 use Drupal\layout_builder\Section;
 use Drupal\layout_builder\SectionComponent;
 use Drupal\Tests\BrowserTestBase;
@@ -41,8 +41,8 @@ protected function setUp() {
     ]);
 
     layout_builder_add_layout_section_field('node', 'bundle_with_section_field');
-    $display = EntityViewDisplay::load('node.bundle_with_section_field.default');
-    $display->setThirdPartySetting('layout_builder', 'allow_custom', TRUE);
+    $display = LayoutBuilderEntityViewDisplay::load('node.bundle_with_section_field.default');
+    $display->setOverridable();
     $display->save();
 
     $this->drupalLogin($this->drupalCreateUser([
@@ -248,7 +248,7 @@ public function testLayoutUrlNoSectionField() {
     ]);
     $node->save();
     $this->drupalGet($node->toUrl('layout-builder'));
-    $this->assertSession()->statusCodeEquals(403);
+    $this->assertSession()->statusCodeEquals(404);
   }
 
   /**
diff --git a/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderCompatibilityTestBase.php b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderCompatibilityTestBase.php
new file mode 100644
index 0000000000..1d638303ab
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderCompatibilityTestBase.php
@@ -0,0 +1,121 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\Kernel;
+
+use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
+
+/**
+ * Tests Layout Builder's compatibility with existing systems.
+ */
+abstract class LayoutBuilderCompatibilityTestBase extends EntityKernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'layout_discovery',
+  ];
+
+  /**
+   * The entity view display.
+   *
+   * @var \Drupal\field_layout\Display\EntityDisplayWithLayoutInterface
+   */
+  protected $display;
+
+  /**
+   * The entity being rendered.
+   *
+   * @var \Drupal\Core\Entity\FieldableEntityInterface
+   */
+  protected $entity;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installEntitySchema('entity_test_base_field_display');
+    $this->installConfig(['filter']);
+
+    // Set up a non-admin user that is allowed to view test entities.
+    \Drupal::currentUser()->setAccount($this->createUser(['uid' => 2], ['view test entity']));
+
+    \Drupal::service('theme_handler')->install(['classy']);
+    $this->config('system.theme')->set('default', 'classy')->save();
+
+    $field_storage = FieldStorageConfig::create([
+      'entity_type' => 'entity_test_base_field_display',
+      'field_name' => 'test_field_display_configurable',
+      'type' => 'boolean',
+    ]);
+    $field_storage->save();
+    FieldConfig::create([
+      'field_storage' => $field_storage,
+      'bundle' => 'entity_test_base_field_display',
+      'label' => 'FieldConfig with configurable display',
+    ])->save();
+
+    $this->display = EntityViewDisplay::create([
+      'targetEntityType' => 'entity_test_base_field_display',
+      'bundle' => 'entity_test_base_field_display',
+      'mode' => 'default',
+      'status' => TRUE,
+    ]);
+    $this->display
+      ->setComponent('test_field_display_configurable', ['region' => 'content', 'weight' => 5])
+      ->save();
+
+    // Create an entity with fields that are configurable and non-configurable.
+    $entity_storage = $this->container->get('entity_type.manager')->getStorage('entity_test_base_field_display');
+    // @todo Remove langcode workarounds after resolving
+    //   https://www.drupal.org/node/2915034.
+    $this->entity = $entity_storage->createWithSampleValues('entity_test_base_field_display', [
+      'langcode' => 'en',
+      'langcode_default' => TRUE,
+    ]);
+    $this->entity->save();
+  }
+
+  /**
+   * Installs the Layout Builder.
+   *
+   * Also configures and reloads the entity display, and reloads the entity.
+   */
+  protected function installLayoutBuilder() {
+    $this->container->get('module_installer')->install(['layout_builder']);
+    $this->refreshServices();
+
+    $this->display = $this->reloadEntity($this->display);
+    $this->display->setOverridable()->save();
+    $this->entity = $this->reloadEntity($this->entity);
+  }
+
+  /**
+   * Asserts that the rendered entity has the correct fields.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity to render.
+   * @param array $attributes
+   *   An array of field attributes to assert.
+   *
+   * @return string
+   *   The rendered string output (typically HTML).
+   */
+  protected function assertFieldAttributes(EntityInterface $entity, array $attributes) {
+    $view_builder = $this->container->get('entity_type.manager')->getViewBuilder($entity->getEntityTypeId());
+    $build = $view_builder->view($entity);
+    $this->render($build);
+
+    $actual = array_map(function (\SimpleXMLElement $element) {
+      return (string) $element->attributes();
+    }, $this->cssSelect('.field'));
+    $this->assertSame($attributes, $actual);
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php
new file mode 100644
index 0000000000..e0800c06b6
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\Kernel;
+
+use Drupal\Core\Config\Schema\SchemaIncompleteException;
+use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
+
+/**
+ * @coversDefaultClass \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay
+ *
+ * @group layout_builder
+ */
+class LayoutBuilderEntityViewDisplayTest extends SectionStorageTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getSectionStorage(array $section_data) {
+    $display = LayoutBuilderEntityViewDisplay::create([
+      'targetEntityType' => 'entity_test',
+      'bundle' => 'entity_test',
+      'mode' => 'default',
+      'status' => TRUE,
+      'third_party_settings' => [
+        'layout_builder' => [
+          'sections' => $section_data,
+        ],
+      ],
+    ]);
+    $display->save();
+    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.
+   */
+  public function testInvalidConfiguration() {
+    $this->setExpectedException(SchemaIncompleteException::class);
+    $this->sectionStorage->getSection(0)->getComponent('first-uuid')->setConfiguration(['bar' => 'baz']);
+    $this->sectionStorage->save();
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderFieldLayoutCompatibilityTest.php b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderFieldLayoutCompatibilityTest.php
index 1ea23218cc..59a76615c1 100644
--- a/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderFieldLayoutCompatibilityTest.php
+++ b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderFieldLayoutCompatibilityTest.php
@@ -2,67 +2,29 @@
 
 namespace Drupal\Tests\layout_builder\Kernel;
 
-use Drupal\Core\Entity\Entity\EntityViewDisplay;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\field\Entity\FieldConfig;
-use Drupal\field\Entity\FieldStorageConfig;
 use Drupal\layout_builder\Section;
-use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
 
 /**
  * Ensures that Layout Builder and Field Layout are compatible with each other.
  *
  * @group layout_builder
  */
-class LayoutBuilderFieldLayoutCompatibilityTest extends EntityKernelTestBase {
+class LayoutBuilderFieldLayoutCompatibilityTest extends LayoutBuilderCompatibilityTestBase {
 
   /**
    * {@inheritdoc}
    */
   public static $modules = [
-    'layout_discovery',
     'field_layout',
   ];
 
-  /**
-   * The entity view display.
-   *
-   * @var \Drupal\field_layout\Display\EntityDisplayWithLayoutInterface
-   */
-  protected $display;
-
   /**
    * {@inheritdoc}
    */
   protected function setUp() {
     parent::setUp();
 
-    $this->installEntitySchema('entity_test_base_field_display');
-    $this->installConfig(['filter']);
-
-    \Drupal::service('theme_handler')->install(['classy']);
-    $this->config('system.theme')->set('default', 'classy')->save();
-
-    $field_storage = FieldStorageConfig::create([
-      'entity_type' => 'entity_test_base_field_display',
-      'field_name' => 'test_field_display_configurable',
-      'type' => 'boolean',
-    ]);
-    $field_storage->save();
-    FieldConfig::create([
-      'field_storage' => $field_storage,
-      'bundle' => 'entity_test_base_field_display',
-      'label' => 'FieldConfig with configurable display',
-    ])->save();
-
-    $this->display = EntityViewDisplay::create([
-      'targetEntityType' => 'entity_test_base_field_display',
-      'bundle' => 'entity_test_base_field_display',
-      'mode' => 'default',
-      'status' => TRUE,
-    ]);
     $this->display
-      ->setComponent('test_field_display_configurable', ['region' => 'content'])
       ->setLayoutId('layout_twocol')
       ->save();
   }
@@ -71,76 +33,47 @@ protected function setUp() {
    * Tests the compatibility of Layout Builder and Field Layout.
    */
   public function testCompatibility() {
-    // Create an entity with fields that are configurable and non-configurable.
-    $entity_storage = $this->container->get('entity_type.manager')->getStorage('entity_test_base_field_display');
-    // @todo Remove langcode workarounds after resolving
-    //   https://www.drupal.org/node/2915034.
-    $entity = $entity_storage->createWithSampleValues('entity_test_base_field_display', [
-      'langcode' => 'en',
-      'langcode_default' => TRUE,
-    ]);
-    $entity->save();
-
     // Ensure that the configurable field is shown in the correct region and
     // that the non-configurable field is shown outside the layout.
-    $original_markup = $this->renderEntity($entity);
+    $expected_fields = [
+      'field field--name-name field--type-string field--label-hidden field__item',
+      'field field--name-test-field-display-configurable field--type-boolean field--label-above',
+      'clearfix text-formatted field field--name-test-display-configurable field--type-text field--label-above',
+      'clearfix text-formatted field field--name-test-display-non-configurable field--type-text field--label-above',
+      'clearfix text-formatted field field--name-test-display-multiple field--type-text field--label-above',
+    ];
+    $this->assertFieldAttributes($this->entity, $expected_fields);
     $this->assertNotEmpty($this->cssSelect('.layout__region--first .field--name-test-display-configurable'));
     $this->assertNotEmpty($this->cssSelect('.layout__region--first .field--name-test-field-display-configurable'));
     $this->assertNotEmpty($this->cssSelect('.field--name-test-display-non-configurable'));
     $this->assertEmpty($this->cssSelect('.layout__region .field--name-test-display-non-configurable'));
 
-    // Install the Layout Builder, configure it for this entity display, and
-    // reload the entity.
-    $this->installModule('layout_builder');
-    $this->display = $this->reloadEntity($this->display);
-    $this->display->setThirdPartySetting('layout_builder', 'allow_custom', TRUE)->save();
-    $entity = $this->reloadEntity($entity);
+    $this->installLayoutBuilder();
 
     // Without using Layout Builder for an override, the result has not changed.
-    $new_markup = $this->renderEntity($entity);
-    $this->assertSame($original_markup, $new_markup);
+    $this->assertFieldAttributes($this->entity, $expected_fields);
 
     // Add a layout override.
     /** @var \Drupal\layout_builder\SectionStorageInterface $field_list */
-    $field_list = $entity->layout_builder__layout;
+    $field_list = $this->entity->get('layout_builder__layout');
     $field_list->appendSection(new Section('layout_onecol'));
-    $entity->save();
+    $this->entity->save();
 
     // The rendered entity has now changed. The non-configurable field is shown
     // outside the layout, the configurable field is not shown at all, and the
     // layout itself is rendered (but empty).
-    $new_markup = $this->renderEntity($entity);
-    $this->assertNotSame($original_markup, $new_markup);
-    $this->assertEmpty($this->cssSelect('.field--name-test-display-configurable'));
-    $this->assertEmpty($this->cssSelect('.field--name-test-field-display-configurable'));
-    $this->assertNotEmpty($this->cssSelect('.field--name-test-display-non-configurable'));
+    $new_expected_fields = [
+      'field field--name-name field--type-string field--label-hidden field__item',
+      'clearfix text-formatted field field--name-test-display-non-configurable field--type-text field--label-above',
+      'clearfix text-formatted field field--name-test-display-multiple field--type-text field--label-above',
+    ];
+    $this->assertFieldAttributes($this->entity, $new_expected_fields);
     $this->assertNotEmpty($this->cssSelect('.layout--onecol'));
 
     // Removing the layout restores the original rendering of the entity.
-    $field_list->removeItem(0);
-    $entity->save();
-    $new_markup = $this->renderEntity($entity);
-    $this->assertSame($original_markup, $new_markup);
-  }
-
-  /**
-   * Renders the provided entity.
-   *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
-   *   The entity to render.
-   * @param string $view_mode
-   *   (optional) The view mode that should be used to render the entity.
-   * @param string $langcode
-   *   (optional) For which language the entity should be rendered, defaults to
-   *   the current content language.
-   *
-   * @return string
-   *   The rendered string output (typically HTML).
-   */
-  protected function renderEntity(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) {
-    $view_builder = $this->container->get('entity_type.manager')->getViewBuilder($entity->getEntityTypeId());
-    $build = $view_builder->view($entity, $view_mode, $langcode);
-    return $this->render($build);
+    $field_list->removeSection(0);
+    $this->entity->save();
+    $this->assertFieldAttributes($this->entity, $expected_fields);
   }
 
 }
diff --git a/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderInstallTest.php b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderInstallTest.php
new file mode 100644
index 0000000000..3873af81b0
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderInstallTest.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\Kernel;
+
+use Drupal\layout_builder\Section;
+
+/**
+ * Ensures that Layout Builder and core EntityViewDisplays are compatible.
+ *
+ * @group layout_builder
+ */
+class LayoutBuilderInstallTest extends LayoutBuilderCompatibilityTestBase {
+
+  /**
+   * Tests the compatibility of Layout Builder with existing entity displays.
+   */
+  public function testCompatibility() {
+    // Ensure that the fields are shown.
+    $expected_fields = [
+      'field field--name-name field--type-string field--label-hidden field__item',
+      'field field--name-test-field-display-configurable field--type-boolean field--label-above',
+      'clearfix text-formatted field field--name-test-display-configurable field--type-text field--label-above',
+      'clearfix text-formatted field field--name-test-display-non-configurable field--type-text field--label-above',
+      'clearfix text-formatted field field--name-test-display-multiple field--type-text field--label-above',
+    ];
+    $this->assertFieldAttributes($this->entity, $expected_fields);
+
+    $this->installLayoutBuilder();
+
+    // Without using Layout Builder for an override, the result has not changed.
+    $this->assertFieldAttributes($this->entity, $expected_fields);
+
+    // Add a layout override.
+    $this->entity->get('layout_builder__layout')->appendSection(new Section('layout_onecol'));
+    $this->entity->save();
+
+    // The rendered entity has now changed. The non-configurable field is shown
+    // outside the layout, the configurable field is not shown at all, and the
+    // layout itself is rendered (but empty).
+    $new_expected_fields = [
+      'field field--name-name field--type-string field--label-hidden field__item',
+      'clearfix text-formatted field field--name-test-display-non-configurable field--type-text field--label-above',
+      'clearfix text-formatted field field--name-test-display-multiple field--type-text field--label-above',
+    ];
+    $this->assertFieldAttributes($this->entity, $new_expected_fields);
+    $this->assertNotEmpty($this->cssSelect('.layout--onecol'));
+
+    // Removing the layout restores the original rendering of the entity.
+    $this->entity->get('layout_builder__layout')->removeSection(0);
+    $this->entity->save();
+    $this->assertFieldAttributes($this->entity, $expected_fields);
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Kernel/LayoutSectionItemListTest.php b/core/modules/layout_builder/tests/src/Kernel/LayoutSectionItemListTest.php
index 4c8ae2e6c9..f3a6e6f950 100644
--- a/core/modules/layout_builder/tests/src/Kernel/LayoutSectionItemListTest.php
+++ b/core/modules/layout_builder/tests/src/Kernel/LayoutSectionItemListTest.php
@@ -24,10 +24,13 @@ class LayoutSectionItemListTest extends SectionStorageTestBase {
   /**
    * {@inheritdoc}
    */
-  protected function getEntity(array $section_data) {
+  protected function getSectionStorage(array $section_data) {
     $this->installEntitySchema('entity_test_base_field_display');
     layout_builder_add_layout_section_field('entity_test_base_field_display', 'entity_test_base_field_display');
 
+    array_map(function ($row) {
+      return ['section' => $row];
+    }, $section_data);
     $entity = EntityTestBaseFieldDisplay::create([
       'name' => 'The test entity',
       'layout_builder__layout' => $section_data,
diff --git a/core/modules/layout_builder/tests/src/Kernel/SectionStorageTestBase.php b/core/modules/layout_builder/tests/src/Kernel/SectionStorageTestBase.php
index b8e8b3462c..97c1fba713 100644
--- a/core/modules/layout_builder/tests/src/Kernel/SectionStorageTestBase.php
+++ b/core/modules/layout_builder/tests/src/Kernel/SectionStorageTestBase.php
@@ -36,18 +36,14 @@ protected function setUp() {
     parent::setUp();
 
     $section_data = [
-      [
-        'section' => new Section('layout_test_plugin', [], [
-          'first-uuid' => new SectionComponent('first-uuid', 'content'),
-        ]),
-      ],
-      [
-        'section' => new Section('layout_test_plugin', ['setting_1' => 'bar'], [
-          'second-uuid' => new SectionComponent('second-uuid', 'content'),
-        ]),
-      ],
+      new Section('layout_test_plugin', [], [
+        'first-uuid' => new SectionComponent('first-uuid', 'content'),
+      ]),
+      new Section('layout_test_plugin', ['setting_1' => 'bar'], [
+        'second-uuid' => new SectionComponent('second-uuid', 'content'),
+      ]),
     ];
-    $this->sectionStorage = $this->getEntity($section_data);
+    $this->sectionStorage = $this->getSectionStorage($section_data);
   }
 
   /**
@@ -59,7 +55,7 @@ protected function setUp() {
    * @return \Drupal\Core\Entity\EntityInterface
    *   The entity.
    */
-  abstract protected function getEntity(array $section_data);
+  abstract protected function getSectionStorage(array $section_data);
 
   /**
    * @covers ::getSections
diff --git a/core/modules/layout_builder/tests/src/Unit/LayoutBuilderRouteEnhancerTest.php b/core/modules/layout_builder/tests/src/Unit/LayoutBuilderRouteEnhancerTest.php
index 2904480d02..62c4924d5b 100644
--- a/core/modules/layout_builder/tests/src/Unit/LayoutBuilderRouteEnhancerTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/LayoutBuilderRouteEnhancerTest.php
@@ -14,84 +14,19 @@
  */
 class LayoutBuilderRouteEnhancerTest extends UnitTestCase {
 
-  /**
-   * @covers ::applies
-   * @dataProvider providerTestApplies
-   */
-  public function testApplies($defaults, $options, $expected) {
-    $route_enhancer = new LayoutBuilderRouteEnhancer();
-    $route = new Route('/some/path', $defaults, [], $options);
-
-    $reflection_method = new \ReflectionMethod($route_enhancer, 'applies');
-    $reflection_method->setAccessible(TRUE);
-    $result = $reflection_method->invoke($route_enhancer, $route);
-    $this->assertSame($expected, $result);
-  }
-
-  /**
-   * Provides test data for ::testApplies().
-   */
-  public function providerTestApplies() {
-    $data = [];
-    $data['layout_builder_true'] = [
-      ['entity_type_id' => 'the_entity_type'],
-      ['_layout_builder' => TRUE],
-      TRUE,
-    ];
-    $data['layout_builder_false'] = [
-      ['entity_type_id' => 'the_entity_type'],
-      ['_layout_builder' => FALSE],
-      FALSE,
-    ];
-    $data['layout_builder_null'] = [
-      ['entity_type_id' => 'the_entity_type'],
-      ['_layout_builder' => NULL],
-      FALSE,
-    ];
-    $data['entity_type_id_empty'] = [
-      ['entity_type_id' => ''],
-      ['_layout_builder' => TRUE],
-      FALSE,
-    ];
-    $data['no_entity_type_id'] = [
-      [],
-      ['_layout_builder' => TRUE],
-      FALSE,
-    ];
-    $data['no_layout_builder'] = [
-      ['entity_type_id' => 'the_entity_type'],
-      [],
-      FALSE,
-    ];
-    $data['empty'] = [
-      [],
-      [],
-      FALSE,
-    ];
-    return $data;
-  }
-
   /**
    * @covers ::enhance
    */
   public function testEnhanceValidDefaults() {
-    $route = new Route('/the/path', ['entity_type_id' => 'the_entity_type'], [], ['_layout_builder' => TRUE]);
+    $route = new Route('/the/path', [], [], ['_layout_builder' => TRUE]);
     $route_enhancer = new LayoutBuilderRouteEnhancer();
-    $object = new \stdClass();
     $defaults = [
-      'entity_type_id' => 'the_entity_type',
-      'the_entity_type' => $object,
-      RouteObjectInterface::ROUTE_NAME => 'the_route_name',
       RouteObjectInterface::ROUTE_OBJECT => $route,
     ];
-    // Ensure that the 'entity' key now contains the value stored for a given
-    // entity type.
+    // Ensure that the 'section_storage' key now contains the value stored for a
+    // given entity type.
     $expected = [
-      'entity_type_id' => 'the_entity_type',
-      'the_entity_type' => $object,
-      RouteObjectInterface::ROUTE_NAME => 'the_route_name',
       RouteObjectInterface::ROUTE_OBJECT => $route,
-      'entity' => $object,
       'is_rebuilding' => TRUE,
     ];
     $result = $route_enhancer->enhance($defaults, new Request(['layout_is_rebuilding' => TRUE]));
@@ -100,47 +35,6 @@ public function testEnhanceValidDefaults() {
     $expected['is_rebuilding'] = FALSE;
     $result = $route_enhancer->enhance($defaults, new Request());
     $this->assertEquals($expected, $result);
-    $this->assertSame($object, $result['entity']);
-
-    // Modifying the original value updates the 'entity' copy.
-    $result['the_entity_type'] = 'something else';
-    $this->assertSame('something else', $result['entity']);
-  }
-
-  /**
-   * @covers ::enhance
-   */
-  public function testEnhanceMissingEntity() {
-    $route_enhancer = new LayoutBuilderRouteEnhancer();
-    $route = new Route('/the/path', ['entity_type_id' => 'the_entity_type'], [], ['_layout_builder' => TRUE]);
-    $defaults = [
-      RouteObjectInterface::ROUTE_NAME => 'the_route',
-      RouteObjectInterface::ROUTE_OBJECT => $route,
-      'entity_type_id' => 'the_entity_type',
-    ];
-    $this->setExpectedException(\RuntimeException::class, 'Failed to find the "the_entity_type" entity in route named the_route');
-    $route_enhancer->enhance($defaults, new Request());
-  }
-
-  /**
-   * Provides test data for ::testEnhanceException().
-   */
-  public function providerTestEnhanceException() {
-    $data = [];
-    $data['missing_entity'] = [
-      [
-        RouteObjectInterface::ROUTE_NAME => 'the_route',
-        'entity_type_id' => 'the_entity_type',
-      ],
-      'Failed to find the "the_entity_type" entity in route named the_route',
-    ];
-    $data['missing_entity_type_id'] = [
-      [
-        RouteObjectInterface::ROUTE_NAME => 'the_route',
-      ],
-      'Failed to find an entity type ID in route named the_route',
-    ];
-    return $data;
   }
 
 }
diff --git a/core/modules/layout_builder/tests/src/Unit/LayoutBuilderRoutesTest.php b/core/modules/layout_builder/tests/src/Unit/LayoutBuilderRoutesTest.php
new file mode 100644
index 0000000000..0d19b2bab0
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Unit/LayoutBuilderRoutesTest.php
@@ -0,0 +1,617 @@
+<?php
+
+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\Tests\UnitTestCase;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouteCollection;
+
+/**
+ * @coversDefaultClass \Drupal\layout_builder\Routing\LayoutBuilderRoutes
+ *
+ * @group layout_builder
+ */
+class LayoutBuilderRoutesTest extends UnitTestCase {
+
+  /**
+   * The Layout Builder route builder.
+   *
+   * @var \Drupal\layout_builder\Routing\LayoutBuilderRoutes
+   */
+  protected $routeBuilder;
+
+  /**
+   * {@inheritdoc}
+   */
+  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());
+  }
+
+  /**
+   * @covers ::getRoutes
+   * @covers ::buildRoute
+   * @covers ::hasIntegerId
+   * @covers ::getEntityTypes
+   */
+  public function testGetRoutes() {
+    $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_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_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_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_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,
+        ]
+      ),
+    ];
+
+    $this->assertEquals($expected, $this->routeBuilder->getRoutes());
+  }
+
+  /**
+   * @covers ::onAlterRoutes
+   * @covers ::buildRoute
+   * @covers ::hasIntegerId
+   * @covers ::getEntityTypes
+   */
+  public function testOnAlterRoutes() {
+    $collection = new RouteCollection();
+    $collection->add('known', new Route('/admin/entity/whatever'));
+    $collection->add('with_bundle', new Route('/admin/entity/{bundle}'));
+    $event = new RouteBuildEvent($collection);
+
+    $expected = [
+      'known' => new Route('/admin/entity/whatever'),
+      'with_bundle' => new Route('/admin/entity/{bundle}'),
+      'entity.entity_view_display.with_field_ui_route.layout_builder' => new Route(
+        '/admin/entity/whatever/display-layout',
+        [
+          'entity_type_id' => 'with_field_ui_route',
+          'view_mode_name' => 'default',
+          '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,
+        ]
+      ),
+      'entity.entity_view_display.with_field_ui_route.layout_builder_save' => new Route(
+        '/admin/entity/whatever/display-layout/save',
+        [
+          'entity_type_id' => 'with_field_ui_route',
+          'view_mode_name' => 'default',
+          '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,
+        ]
+      ),
+      'entity.entity_view_display.with_field_ui_route.layout_builder_cancel' => new Route(
+        '/admin/entity/whatever/display-layout/cancel',
+        [
+          'entity_type_id' => 'with_field_ui_route',
+          'view_mode_name' => 'default',
+          '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,
+        ]
+      ),
+      'entity.entity_view_display.with_bundle_key.layout_builder' => new Route(
+        '/admin/entity/whatever/display-layout',
+        [
+          'entity_type_id' => 'with_bundle_key',
+          'view_mode_name' => 'default',
+          '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,
+        ]
+      ),
+      'entity.entity_view_display.with_bundle_key.layout_builder_save' => new Route(
+        '/admin/entity/whatever/display-layout/save',
+        [
+          'entity_type_id' => 'with_bundle_key',
+          'view_mode_name' => 'default',
+          '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,
+        ]
+      ),
+      'entity.entity_view_display.with_bundle_key.layout_builder_cancel' => new Route(
+        '/admin/entity/whatever/display-layout/cancel',
+        [
+          'entity_type_id' => 'with_bundle_key',
+          'view_mode_name' => 'default',
+          '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,
+        ]
+      ),
+      'entity.entity_view_display.with_bundle_parameter.layout_builder' => new Route(
+        '/admin/entity/{bundle}/display-layout',
+        [
+          'entity_type_id' => 'with_bundle_parameter',
+          'view_mode_name' => 'default',
+          '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,
+        ]
+      ),
+      'entity.entity_view_display.with_bundle_parameter.layout_builder_save' => new Route(
+        '/admin/entity/{bundle}/display-layout/save',
+        [
+          'entity_type_id' => 'with_bundle_parameter',
+          'view_mode_name' => 'default',
+          '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,
+        ]
+      ),
+      'entity.entity_view_display.with_bundle_parameter.layout_builder_cancel' => new Route(
+        '/admin/entity/{bundle}/display-layout/cancel',
+        [
+          'entity_type_id' => 'with_bundle_parameter',
+          'view_mode_name' => 'default',
+          '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,
+        ]
+      ),
+    ];
+
+    $this->routeBuilder->onAlterRoutes($event);
+    $this->assertEquals($expected, $event->getRouteCollection()->all());
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreParamConverterTest.php b/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreParamConverterTest.php
new file mode 100644
index 0000000000..3c3c9f4065
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreParamConverterTest.php
@@ -0,0 +1,86 @@
+<?php
+
+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\SectionStorageInterface;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\layout_builder\Routing\LayoutTempstoreParamConverter
+ *
+ * @group layout_builder
+ */
+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());
+
+    $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());
+    $layout_tempstore_repository->get($section_storage->reveal())->willReturn($expected);
+
+    $result = $converter->convert($value, $definition, $name, $defaults);
+    $this->assertEquals($expected, $result);
+  }
+
+  /**
+   * @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());
+
+    $value = 'some_value';
+    $definition = ['layout_builder_tempstore' => TRUE];
+    $name = 'the_parameter_name';
+    $defaults = ['section_storage_type' => NULL];
+
+    $class_resolver->getInstanceFromDefinition()->shouldNotBeCalled();
+    $layout_tempstore_repository->get()->shouldNotBeCalled();
+
+    $result = $converter->convert($value, $definition, $name, $defaults);
+    $this->assertNull($result);
+  }
+
+  /**
+   * @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());
+
+    $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);
+    $layout_tempstore_repository->get()->shouldNotBeCalled();
+
+    $result = $converter->convert($value, $definition, $name, $defaults);
+    $this->assertNull($result);
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreRepositoryTest.php b/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreRepositoryTest.php
index a652d4a56d..75502d5f2e 100644
--- a/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreRepositoryTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreRepositoryTest.php
@@ -2,12 +2,8 @@
 
 namespace Drupal\Tests\layout_builder\Unit;
 
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityStorageInterface;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Entity\RevisionableInterface;
-use Drupal\Core\Language\Language;
 use Drupal\layout_builder\LayoutTempstoreRepository;
+use Drupal\layout_builder\SectionStorageInterface;
 use Drupal\Tests\UnitTestCase;
 use Drupal\user\SharedTempStore;
 use Drupal\user\SharedTempStoreFactory;
@@ -19,115 +15,64 @@
 class LayoutTempstoreRepositoryTest extends UnitTestCase {
 
   /**
-   * @covers ::getFromId
    * @covers ::get
-   * @covers ::generateTempstoreId
    */
-  public function testGetFromIdEmptyTempstore() {
+  public function testGetEmptyTempstore() {
+    $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('the_entity_id.en')->shouldBeCalled();
+    $tempstore->get('my_storage_id')->shouldBeCalled();
 
     $tempstore_factory = $this->prophesize(SharedTempStoreFactory::class);
-    $tempstore_factory->get('the_entity_type_id.layout_builder__layout')->willReturn($tempstore->reveal());
-
-    $entity = $this->prophesize(EntityInterface::class);
-    $entity->getEntityTypeId()->willReturn('the_entity_type_id');
-    $entity->id()->willReturn('the_entity_id');
-    $entity->language()->willReturn(new Language(['id' => 'en']));
-
-    $entity_storage = $this->prophesize(EntityStorageInterface::class);
-    $entity_storage->loadRevision('the_entity_id')->willReturn($entity->reveal());
+    $tempstore_factory->get('layout_builder.my_storage_type')->willReturn($tempstore->reveal());
 
-    $entity_type_manager = $this->prophesize(EntityTypeManagerInterface::class);
-    $entity_type_manager->getStorage('the_entity_type_id')->willReturn($entity_storage->reveal());
+    $repository = new LayoutTempstoreRepository($tempstore_factory->reveal());
 
-    $repository = new LayoutTempstoreRepository($tempstore_factory->reveal(), $entity_type_manager->reveal());
-
-    $result = $repository->getFromId('the_entity_type_id', 'the_entity_id');
-    $this->assertSame($entity->reveal(), $result);
+    $result = $repository->get($section_storage->reveal());
+    $this->assertSame($section_storage->reveal(), $result);
   }
 
   /**
-   * @covers ::getFromId
    * @covers ::get
-   * @covers ::generateTempstoreId
    */
-  public function testGetFromIdLoadedTempstore() {
-    $tempstore_entity = $this->prophesize(EntityInterface::class);
-    $tempstore = $this->prophesize(SharedTempStore::class);
-    $tempstore->get('the_entity_id.en')->willReturn(['entity' => $tempstore_entity->reveal()]);
-    $tempstore_factory = $this->prophesize(SharedTempStoreFactory::class);
-    $tempstore_factory->get('the_entity_type_id.layout_builder__layout')->willReturn($tempstore->reveal());
-
-    $entity = $this->prophesize(EntityInterface::class);
-    $entity->getEntityTypeId()->willReturn('the_entity_type_id');
-    $entity->id()->willReturn('the_entity_id');
-    $entity->language()->willReturn(new Language(['id' => 'en']));
-
-    $entity_storage = $this->prophesize(EntityStorageInterface::class);
-    $entity_storage->loadRevision('the_entity_id')->willReturn($entity->reveal());
-
-    $entity_type_manager = $this->prophesize(EntityTypeManagerInterface::class);
-    $entity_type_manager->getStorage('the_entity_type_id')->willReturn($entity_storage->reveal());
-
-    $repository = new LayoutTempstoreRepository($tempstore_factory->reveal(), $entity_type_manager->reveal());
-
-    $result = $repository->getFromId('the_entity_type_id', 'the_entity_id');
-    $this->assertSame($tempstore_entity->reveal(), $result);
-    $this->assertNotSame($entity->reveal(), $result);
-  }
+  public function testGetLoadedTempstore() {
+    $section_storage = $this->prophesize(SectionStorageInterface::class);
+    $section_storage->getStorageType()->willReturn('my_storage_type');
+    $section_storage->getStorageId()->willReturn('my_storage_id');
 
-  /**
-   * @covers ::getFromId
-   * @covers ::get
-   * @covers ::generateTempstoreId
-   */
-  public function testGetFromIdRevisionable() {
+    $tempstore_section_storage = $this->prophesize(SectionStorageInterface::class);
     $tempstore = $this->prophesize(SharedTempStore::class);
-    $tempstore->get('the_entity_id.en.the_revision_id')->shouldBeCalled();
-
+    $tempstore->get('my_storage_id')->willReturn(['section_storage' => $tempstore_section_storage->reveal()]);
     $tempstore_factory = $this->prophesize(SharedTempStoreFactory::class);
-    $tempstore_factory->get('the_entity_type_id.layout_builder__layout')->willReturn($tempstore->reveal());
-
-    $entity = $this->prophesize(EntityInterface::class)->willImplement(RevisionableInterface::class);
-    $entity->getEntityTypeId()->willReturn('the_entity_type_id');
-    $entity->id()->willReturn('the_entity_id');
-    $entity->language()->willReturn(new Language(['id' => 'en']));
-    $entity->getRevisionId()->willReturn('the_revision_id');
+    $tempstore_factory->get('layout_builder.my_storage_type')->willReturn($tempstore->reveal());
 
-    $entity_storage = $this->prophesize(EntityStorageInterface::class);
-    $entity_storage->loadRevision('the_entity_id')->willReturn($entity->reveal());
+    $repository = new LayoutTempstoreRepository($tempstore_factory->reveal());
 
-    $entity_type_manager = $this->prophesize(EntityTypeManagerInterface::class);
-    $entity_type_manager->getStorage('the_entity_type_id')->willReturn($entity_storage->reveal());
-
-    $repository = new LayoutTempstoreRepository($tempstore_factory->reveal(), $entity_type_manager->reveal());
-
-    $result = $repository->getFromId('the_entity_type_id', 'the_entity_id');
-    $this->assertSame($entity->reveal(), $result);
+    $result = $repository->get($section_storage->reveal());
+    $this->assertSame($tempstore_section_storage->reveal(), $result);
+    $this->assertNotSame($section_storage->reveal(), $result);
   }
 
   /**
    * @covers ::get
    */
-  public function testGetInvalidEntity() {
+  public function testGetInvalidEntry() {
+    $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('the_entity_id.en')->willReturn(['entity' => 'this_is_not_an_entity']);
+    $tempstore->get('my_storage_id')->willReturn(['section_storage' => 'this_is_not_an_entity']);
 
     $tempstore_factory = $this->prophesize(SharedTempStoreFactory::class);
-    $tempstore_factory->get('the_entity_type_id.layout_builder__layout')->willReturn($tempstore->reveal());
-
-    $entity_type_manager = $this->prophesize(EntityTypeManagerInterface::class);
-
-    $repository = new LayoutTempstoreRepository($tempstore_factory->reveal(), $entity_type_manager->reveal());
+    $tempstore_factory->get('layout_builder.my_storage_type')->willReturn($tempstore->reveal());
 
-    $entity = $this->prophesize(EntityInterface::class);
-    $entity->language()->willReturn(new Language(['id' => 'en']));
-    $entity->getEntityTypeId()->willReturn('the_entity_type_id');
-    $entity->id()->willReturn('the_entity_id');
+    $repository = new LayoutTempstoreRepository($tempstore_factory->reveal());
 
-    $this->setExpectedException(\UnexpectedValueException::class, 'The entry with entity type "the_entity_type_id" and ID "the_entity_id.en" is not a valid entity');
-    $repository->get($entity->reveal());
+    $this->setExpectedException(\UnexpectedValueException::class, 'The entry with storage type "my_storage_type" and ID "my_storage_id" is invalid');
+    $repository->get($section_storage->reveal());
   }
 
 }
diff --git a/core/modules/layout_builder/tests/src/Unit/SectionStorageDefaultsParamConverterTest.php b/core/modules/layout_builder/tests/src/Unit/SectionStorageDefaultsParamConverterTest.php
new file mode 100644
index 0000000000..df07c86cc6
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Unit/SectionStorageDefaultsParamConverterTest.php
@@ -0,0 +1,111 @@
+<?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;
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Unit/SectionStorageOverridesParamConverterTest.php b/core/modules/layout_builder/tests/src/Unit/SectionStorageOverridesParamConverterTest.php
new file mode 100644
index 0000000000..f0c01468e5
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Unit/SectionStorageOverridesParamConverterTest.php
@@ -0,0 +1,119 @@
+<?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;
+  }
+
+}
