diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml
index 95311ada2b..3b5bbe4190 100644
--- a/core/config/schema/core.data_types.schema.yml
+++ b/core/config/schema/core.data_types.schema.yml
@@ -284,6 +284,9 @@ config_entity:
     _core:
       type: _core_config_info
 
+block.settings.*:
+  type: block_settings
+
 block_settings:
   type: mapping
   label: 'Block settings'
diff --git a/core/lib/Drupal/Core/Entity/EntityDisplayBase.php b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php
index 2a3945bff8..927fdeb4c6 100644
--- a/core/lib/Drupal/Core/Entity/EntityDisplayBase.php
+++ b/core/lib/Drupal/Core/Entity/EntityDisplayBase.php
@@ -194,7 +194,7 @@ protected function init() {
           }
           elseif ($options) {
             $options += ['region' => $default_region];
-            $this->content[$name] = $this->pluginManager->prepareConfiguration($definition->getType(), $options);
+            $this->setComponent($name, $options);
           }
           // Note: (base) fields that do not specify display options are not
           // tracked in the display at all, in order to avoid cluttering the
diff --git a/core/modules/block/config/schema/block.schema.yml b/core/modules/block/config/schema/block.schema.yml
index 16d79bce2b..7dc4f53d1c 100644
--- a/core/modules/block/config/schema/block.schema.yml
+++ b/core/modules/block/config/schema/block.schema.yml
@@ -30,6 +30,3 @@ block.block.*:
       sequence:
         type: condition.plugin.[id]
         label: 'Visibility Condition'
-
-block.settings.*:
-  type: block_settings
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..83a999e897 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,33 @@ 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: 'Per-view-mode layout settings'
+  mapping:
+    layout_id:
+      type: string
+      label: 'Layout ID'
+    layout_settings:
+      type: layout_plugin.settings.[%parent.id]
+      label: 'Layout settings'
+    section_data:
+      type: sequence
+      label: 'Section data'
+      sequence:
+        type: mapping
+        mapping:
+          configuration:
+            type: block.settings.[id]
+            label: 'Block configuration'
+          region:
+            type: string
+            label: 'Region'
+          weight:
+            type: integer
+            label: 'Weight'
diff --git a/core/modules/layout_builder/layout_builder.install b/core/modules/layout_builder/layout_builder.install
new file mode 100644
index 0000000000..74e7e5766e
--- /dev/null
+++ b/core/modules/layout_builder/layout_builder.install
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains install and update functions for Layout Builder.
+ */
+
+use Drupal\Core\Cache\Cache;
+use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
+
+/**
+ * Implements hook_install().
+ */
+function layout_builder_install() {
+  $displays = LayoutBuilderEntityViewDisplay::loadMultiple();
+  /** @var \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface[] $displays */
+  foreach ($displays as $display) {
+    // Migrate Field Layout settings to the first section.
+    $field_layout_settings = $display->getThirdPartySettings('field_layout');
+    if (isset($field_layout_settings['id'])) {
+      $section = [
+        'layout_id' => $field_layout_settings['id'],
+        'layout_settings' => isset($field_layout_settings['settings']) ? $field_layout_settings['settings'] : [],
+      ];
+      $display->setThirdPartySetting('layout_builder', 'sections', [$section]);
+    }
+
+    // Resave each component to populate the section data.
+    foreach ($display->getComponents() as $name => $component) {
+      $display->setComponent($name, $component);
+    }
+    $display->save();
+  }
+  Cache::invalidateTags(['rendered']);
+}
diff --git a/core/modules/layout_builder/layout_builder.module b/core/modules/layout_builder/layout_builder.module
index 2192168cb0..13398d8ecb 100644
--- a/core/modules/layout_builder/layout_builder.module
+++ b/core/modules/layout_builder/layout_builder.module
@@ -5,12 +5,15 @@
  * 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\LayoutEntity;
+use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
 
 /**
  * Implements hook_help().
@@ -35,6 +38,10 @@ 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);
+  if (\Drupal::moduleHandler()->moduleExists('field_ui')) {
+    $entity_types['entity_view_display']->setFormClass('edit', EntityViewDisplayEditForm::class);
+  }
 }
 
 /**
@@ -64,7 +71,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 +96,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,23 +107,30 @@ 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();
 
     if ($new_value) {
       layout_builder_add_layout_section_field($entity_type_id, $bundle);
+      // Clear definitions after creating a new field.
+      $display->clearCachedDefinitions();
+      // Force the layout to render with no label.
+      $display->setComponent('layout_builder__layout', [
+        'label' => 'hidden',
+        'region' => '__layout_builder',
+      ]);
     }
     elseif ($field = FieldConfig::loadByName($entity_type_id, $bundle, 'layout_builder__layout')) {
       $field->delete();
@@ -161,27 +175,13 @@ function layout_builder_add_layout_section_field($entity_type_id, $bundle, $fiel
   return $field;
 }
 
-/**
- * Implements hook_entity_view_display_alter().
- */
-function layout_builder_entity_view_display_alter(EntityViewDisplayInterface $display, array $context) {
-  if ($display->getThirdPartySetting('layout_builder', 'allow_custom', FALSE)) {
-    // Force the layout to render with no label.
-    $display->setComponent('layout_builder__layout', [
-      'label' => 'hidden',
-      'region' => '__layout_builder',
-    ]);
-  }
-  else {
-    $display->removeComponent('layout_builder__layout');
-  }
-}
-
 /**
  * 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()) {
+function layout_builder_entity_view_alter(array &$build, EntityInterface $entity, LayoutEntityDisplayInterface $display) {
+  $entity = new LayoutEntity($entity);
+  $display = new LayoutEntity($display);
+  if (!$entity->isLayoutEmpty()) {
     // 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']);
@@ -197,4 +197,10 @@ function layout_builder_entity_view_alter(array &$build, EntityInterface $entity
       }
     }
   }
+  elseif (!$display->isLayoutEmpty()) {
+    $builder = \Drupal::service('layout_builder.builder');
+    foreach ($display->getSections() as $delta => $section) {
+      $builder->alterBuild($build, $delta, $section);
+    }
+  }
 }
diff --git a/core/modules/layout_builder/layout_builder.services.yml b/core/modules/layout_builder/layout_builder.services.yml
index 518d9ee942..be6fb111f4 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.builder:
     class: Drupal\layout_builder\LayoutSectionBuilder
-    arguments: ['@current_user', '@plugin.manager.core.layout', '@plugin.manager.block', '@context.handler', '@context.repository']
+    arguments: ['@current_user', '@plugin.manager.block', '@context.handler', '@context.repository']
   layout_builder.tempstore_repository:
     class: Drupal\layout_builder\LayoutTempstoreRepository
     arguments: ['@user.shared_tempstore', '@entity_type.manager']
diff --git a/core/modules/layout_builder/src/Access/LayoutSectionAccessCheck.php b/core/modules/layout_builder/src/Access/LayoutSectionAccessCheck.php
index e13a149238..1b5044eb2b 100644
--- a/core/modules/layout_builder/src/Access/LayoutSectionAccessCheck.php
+++ b/core/modules/layout_builder/src/Access/LayoutSectionAccessCheck.php
@@ -4,10 +4,10 @@
 
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
-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\Entity\LayoutEntity;
 
 /**
  * Provides an access check for the Layout Builder UI.
@@ -54,8 +54,8 @@ public function access(RouteMatchInterface $route_match, AccountInterface $accou
       return AccessResult::forbidden()->addCacheContexts(['route']);
     }
 
-    // If the entity isn't fieldable, forbid access.
-    if (!$entity instanceof FieldableEntityInterface || !$entity->hasField('layout_builder__layout')) {
+    // If the entity doesn't support layout, forbid access.
+    if (!$entity instanceof LayoutEntity || !$entity->isLayoutEnabled()) {
       $access = AccessResult::forbidden();
     }
     else {
diff --git a/core/modules/layout_builder/src/Cache/LayoutBuilderIsActiveCacheContext.php b/core/modules/layout_builder/src/Cache/LayoutBuilderIsActiveCacheContext.php
index c632f4b33a..b68bd55433 100644
--- a/core/modules/layout_builder/src/Cache/LayoutBuilderIsActiveCacheContext.php
+++ b/core/modules/layout_builder/src/Cache/LayoutBuilderIsActiveCacheContext.php
@@ -6,6 +6,7 @@
 use Drupal\Core\Cache\Context\CalculatedCacheContextInterface;
 use Drupal\Core\Entity\Entity\EntityViewDisplay;
 use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\layout_builder\Entity\LayoutEntity;
 
 /**
  * Determines whether Layout Builder is active for a given entity type or not.
@@ -49,7 +50,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';
   }
 
   /**
@@ -75,11 +76,14 @@ public function getCacheableMetadata($entity_type_id = NULL) {
    * @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') {
     if ($entity = $this->routeMatch->getParameter($entity_type_id)) {
+      if ($entity instanceof LayoutEntity) {
+        $entity = $entity->getEntity();
+      }
       return EntityViewDisplay::collectRenderDisplay($entity, $view_mode);
     }
   }
diff --git a/core/modules/layout_builder/src/Controller/AddSectionController.php b/core/modules/layout_builder/src/Controller/AddSectionController.php
index d677108238..28bb70ed23 100644
--- a/core/modules/layout_builder/src/Controller/AddSectionController.php
+++ b/core/modules/layout_builder/src/Controller/AddSectionController.php
@@ -4,8 +4,9 @@
 
 use Drupal\Core\DependencyInjection\ClassResolverInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\Core\Entity\EntityInterface;
+use Drupal\layout_builder\Entity\LayoutEntity;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
+use Drupal\layout_builder\Section;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
@@ -52,7 +53,7 @@ public static function create(ContainerInterface $container) {
   /**
    * Add the layout to the entity field in a tempstore.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity.
    * @param int $delta
    *   The delta of the section to splice.
@@ -62,14 +63,8 @@ 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\Field\LayoutSectionItemListInterface $field_list */
-    $field_list = $entity->layout_builder__layout;
-    $field_list->addItem($delta, [
-      'layout' => $plugin_id,
-      'layout_settings' => [],
-      'section' => [],
-    ]);
+  public function build(LayoutEntity $entity, $delta, $plugin_id) {
+    $entity->addSection($delta, new Section($plugin_id));
 
     $this->layoutTempstoreRepository->set($entity);
 
diff --git a/core/modules/layout_builder/src/Controller/ChooseBlockController.php b/core/modules/layout_builder/src/Controller/ChooseBlockController.php
index 9eddb79fc3..c0fcc0ab75 100644
--- a/core/modules/layout_builder/src/Controller/ChooseBlockController.php
+++ b/core/modules/layout_builder/src/Controller/ChooseBlockController.php
@@ -4,8 +4,8 @@
 
 use Drupal\Core\Block\BlockManagerInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Url;
+use Drupal\layout_builder\Entity\LayoutEntity;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -46,7 +46,7 @@ public static function create(ContainerInterface $container) {
   /**
    * Provides the UI for choosing a new block.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity.
    * @param int $delta
    *   The delta of the section to splice.
@@ -56,7 +56,7 @@ public static function create(ContainerInterface $container) {
    * @return array
    *   A render array.
    */
-  public function build(EntityInterface $entity, $delta, $region) {
+  public function build(LayoutEntity $entity, $delta, $region) {
     $build['#type'] = 'container';
     $build['#attributes']['class'][] = 'block-categories';
 
diff --git a/core/modules/layout_builder/src/Controller/ChooseSectionController.php b/core/modules/layout_builder/src/Controller/ChooseSectionController.php
index 0414d2abf1..baa7d53eaf 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\Entity\LayoutEntity;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -49,7 +49,7 @@ public static function create(ContainerInterface $container) {
   /**
    * Choose a layout plugin to add as a section.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity.
    * @param int $delta
    *   The delta of the section to splice.
@@ -57,7 +57,7 @@ public static function create(ContainerInterface $container) {
    * @return array
    *   The render array.
    */
-  public function build(EntityInterface $entity, $delta) {
+  public function build(LayoutEntity $entity, $delta) {
     $output['#title'] = $this->t('Choose a layout');
 
     $items = [];
diff --git a/core/modules/layout_builder/src/Controller/LayoutBuilderController.php b/core/modules/layout_builder/src/Controller/LayoutBuilderController.php
index a4163a40a8..0c0f56849a 100644
--- a/core/modules/layout_builder/src/Controller/LayoutBuilderController.php
+++ b/core/modules/layout_builder/src/Controller/LayoutBuilderController.php
@@ -4,14 +4,13 @@
 
 use Drupal\Core\Block\BlockManagerInterface;
 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\Entity\LayoutEntity;
 use Drupal\layout_builder\LayoutSectionBuilder;
-use Drupal\layout_builder\Field\LayoutSectionItemInterface;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
+use Drupal\layout_builder\Section;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
@@ -31,13 +30,6 @@ class LayoutBuilderController implements ContainerInjectionInterface {
    */
   protected $builder;
 
-  /**
-   * The layout manager.
-   *
-   * @var \Drupal\Core\Layout\LayoutPluginManagerInterface
-   */
-  protected $layoutManager;
-
   /**
    * The block manager.
    *
@@ -57,16 +49,13 @@ class LayoutBuilderController implements ContainerInjectionInterface {
    *
    * @param \Drupal\layout_builder\LayoutSectionBuilder $builder
    *   The layout section builder.
-   * @param \Drupal\Core\Layout\LayoutPluginManagerInterface $layout_manager
-   *   The layout manager.
    * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
    *   The block manager.
    * @param \Drupal\layout_builder\LayoutTempstoreRepositoryInterface $layout_tempstore_repository
    *   The layout tempstore repository.
    */
-  public function __construct(LayoutSectionBuilder $builder, LayoutPluginManagerInterface $layout_manager, BlockManagerInterface $block_manager, LayoutTempstoreRepositoryInterface $layout_tempstore_repository) {
+  public function __construct(LayoutSectionBuilder $builder, BlockManagerInterface $block_manager, LayoutTempstoreRepositoryInterface $layout_tempstore_repository) {
     $this->builder = $builder;
-    $this->layoutManager = $layout_manager;
     $this->blockManager = $block_manager;
     $this->layoutTempstoreRepository = $layout_tempstore_repository;
   }
@@ -77,7 +66,6 @@ public function __construct(LayoutSectionBuilder $builder, LayoutPluginManagerIn
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('layout_builder.builder'),
-      $container->get('plugin.manager.core.layout'),
       $container->get('plugin.manager.block'),
       $container->get('layout_builder.tempstore_repository')
     );
@@ -86,20 +74,20 @@ public static function create(ContainerInterface $container) {
   /**
    * Provides a title callback.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity.
    *
    * @return string
    *   The title for the layout page.
    */
-  public function title(EntityInterface $entity) {
+  public function title(LayoutEntity $entity) {
     return $this->t('Edit layout for %label', ['%label' => $entity->label()]);
   }
 
   /**
    * Renders the Layout UI.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity.
    * @param bool $is_rebuilding
    *   (optional) Indicates if the layout is rebuilding, defaults to FALSE.
@@ -107,24 +95,21 @@ public function title(EntityInterface $entity) {
    * @return array
    *   A render array.
    */
-  public function layout(EntityInterface $entity, $is_rebuilding = FALSE) {
+  public function layout(LayoutEntity $entity, $is_rebuilding = FALSE) {
     $entity_id = $entity->id();
     $entity_type_id = $entity->getEntityTypeId();
 
-    /** @var \Drupal\layout_builder\Field\LayoutSectionItemListInterface $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->isEmpty()) {
-      $field_list->addItem(0, ['layout' => 'layout_onecol']);
+    if (!$is_rebuilding && $entity->isLayoutEmpty()) {
+      $entity->addSection(0, new Section('layout_onecol'));
       $this->layoutTempstoreRepository->set($entity);
     }
 
     $output = [];
     $count = 0;
-    foreach ($field_list as $item) {
+    foreach ($entity->getSections() as $section) {
       $output[] = $this->buildAddSectionLink($entity_type_id, $entity_id, $count);
-      $output[] = $this->buildAdministrativeSection($item, $entity, $count);
+      $output[] = $this->buildAdministrativeSection($section, $entity, $count);
       $count++;
     }
     $output[] = $this->buildAddSectionLink($entity_type_id, $entity_id, $count);
@@ -179,9 +164,9 @@ protected function buildAddSectionLink($entity_type_id, $entity_id, $delta) {
   /**
    * Builds the render array for the layout section while editing.
    *
-   * @param \Drupal\layout_builder\Field\LayoutSectionItemInterface $item
-   *   The layout section item.
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Section $section
+   *   The layout section.
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity.
    * @param int $delta
    *   The delta of the section.
@@ -189,12 +174,12 @@ protected function buildAddSectionLink($entity_type_id, $entity_id, $delta) {
    * @return array
    *   The render array for a given section.
    */
-  protected function buildAdministrativeSection(LayoutSectionItemInterface $item, EntityInterface $entity, $delta) {
+  protected function buildAdministrativeSection(Section $section, LayoutEntity $entity, $delta) {
     $entity_type_id = $entity->getEntityTypeId();
     $entity_id = $entity->id();
 
-    $layout = $this->layoutManager->createInstance($item->layout, $item->layout_settings);
-    $build = $this->builder->buildSectionFromLayout($layout, $item->section);
+    $layout = $section->getLayout();
+    $build = $this->builder->buildSection($section);
     $layout_definition = $layout->getPluginDefinition();
 
     foreach ($layout_definition->getRegions() as $region => $info) {
@@ -290,13 +275,13 @@ protected function buildAdministrativeSection(LayoutSectionItemInterface $item,
   /**
    * Saves the layout.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity.
    *
    * @return \Symfony\Component\HttpFoundation\RedirectResponse
    *   A redirect response.
    */
-  public function saveLayout(EntityInterface $entity) {
+  public function saveLayout(LayoutEntity $entity) {
     $entity->save();
     $this->layoutTempstoreRepository->delete($entity);
     return new RedirectResponse($entity->toUrl()->setAbsolute()->toString());
@@ -305,13 +290,13 @@ public function saveLayout(EntityInterface $entity) {
   /**
    * Cancels the layout.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity.
    *
    * @return \Symfony\Component\HttpFoundation\RedirectResponse
    *   A redirect response.
    */
-  public function cancelLayout(EntityInterface $entity) {
+  public function cancelLayout(LayoutEntity $entity) {
     $this->layoutTempstoreRepository->delete($entity);
     return new RedirectResponse($entity->toUrl()->setAbsolute()->toString());
   }
diff --git a/core/modules/layout_builder/src/Controller/LayoutRebuildTrait.php b/core/modules/layout_builder/src/Controller/LayoutRebuildTrait.php
index 53fd4e8b0a..2c38d0e2fd 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\Entity\LayoutEntity;
 
 /**
  * Provides AJAX responses to rebuild the Layout Builder.
@@ -24,14 +24,14 @@
   /**
    * Rebuilds the layout.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity.
    *
    * @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) {
+  protected function rebuildAndClose(LayoutEntity $entity) {
     $response = $this->rebuildLayout($entity);
     $response->addCommand(new CloseDialogCommand('#drupal-off-canvas'));
     return $response;
@@ -40,14 +40,14 @@ protected function rebuildAndClose(EntityInterface $entity) {
   /**
    * Rebuilds the layout.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity.
    *
    * @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(LayoutEntity $entity) {
     $response = new AjaxResponse();
     $layout_controller = $this->classResolver->getInstanceFromDefinition(LayoutBuilderController::class);
     $layout = $layout_controller->layout($entity, TRUE);
diff --git a/core/modules/layout_builder/src/Controller/MoveBlockController.php b/core/modules/layout_builder/src/Controller/MoveBlockController.php
index d648416d9e..1a8dedacaf 100644
--- a/core/modules/layout_builder/src/Controller/MoveBlockController.php
+++ b/core/modules/layout_builder/src/Controller/MoveBlockController.php
@@ -4,7 +4,7 @@
 
 use Drupal\Core\DependencyInjection\ClassResolverInterface;
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\Core\Entity\EntityInterface;
+use Drupal\layout_builder\Entity\LayoutEntity;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -50,7 +50,7 @@ public static function create(ContainerInterface $container) {
   /**
    * Moves a block to another region.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity.
    * @param int $delta_from
    *   The delta of the original section.
@@ -68,20 +68,17 @@ 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\Field\LayoutSectionItemInterface $field */
-    $field = $entity->layout_builder__layout->get($delta_from);
-    $section = $field->getSection();
+  public function build(LayoutEntity $entity, $delta_from, $delta_to, $region_from, $region_to, $block_uuid, $preceding_block_uuid = NULL) {
+    $section = $entity->getSection($delta_from);
 
-    $block = $section->getBlock($region_from, $block_uuid);
-    $section->removeBlock($region_from, $block_uuid);
+    $block = $section->getBlock($block_uuid);
+    $section->removeBlock($block_uuid);
 
     // If the block is moving from one section to another, update the original
     // section and load the new one.
     if ($delta_from !== $delta_to) {
-      $field->updateFromSection($section);
-      $field = $entity->layout_builder__layout->get($delta_to);
-      $section = $field->getSection();
+      $entity->updateSection($delta_from, $section);
+      $section = $entity->getSection($delta_to);
     }
 
     // If a preceding block was specified, insert after that. Otherwise add the
@@ -93,7 +90,7 @@ public function build(EntityInterface $entity, $delta_from, $delta_to, $region_f
       $section->addBlock($region_to, $block_uuid, $block);
     }
 
-    $field->updateFromSection($section);
+    $entity->updateSection($delta_to, $section);
 
     $this->layoutTempstoreRepository->set($entity);
     return $this->rebuildLayout($entity);
diff --git a/core/modules/layout_builder/src/Entity/EntityDecorator.php b/core/modules/layout_builder/src/Entity/EntityDecorator.php
new file mode 100644
index 0000000000..616617ac8e
--- /dev/null
+++ b/core/modules/layout_builder/src/Entity/EntityDecorator.php
@@ -0,0 +1,407 @@
+<?php
+
+namespace Drupal\layout_builder\Entity;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * Provides a base class for entity decorators to extend.
+ *
+ * @todo Move to \Drupal\Core\Entity in https://www.drupal.org/node/2924796.
+ */
+abstract class EntityDecorator implements EntityInterface {
+
+  /**
+   * The decorated entity.
+   *
+   * @var \Drupal\Core\Entity\EntityInterface
+   */
+  protected $subject;
+
+  /**
+   * LayoutEntity constructor.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $subject
+   *   The entity being decorated.
+   */
+  public function __construct(EntityInterface $subject) {
+    $this->subject = $subject instanceof static ? $subject->getEntity() : $subject;
+  }
+
+  /**
+   * Passes through all unknown calls onto the subject.
+   */
+  public function __call($method, $args) {
+    return call_user_func_array([$this->subject, $method], $args);
+  }
+
+  /**
+   * Implements the magic method for getting object properties.
+   */
+  public function &__get($name) {
+    $value = &$this->subject->{$name};
+    return $value;
+  }
+
+  /**
+   * Implements the magic method for setting object properties.
+   */
+  public function __set($name, $value) {
+    $this->subject->{$name} = $value;
+  }
+
+  /**
+   * Implements the magic method for isset().
+   */
+  public function __isset($name) {
+    return isset($this->subject->{$name});
+  }
+
+  /**
+   * Implements the magic method for unset().
+   */
+  public function __unset($name) {
+    unset($this->subject->{$name});
+  }
+
+  /**
+   * Gets the decorated entity.
+   *
+   * @return \Drupal\Core\Entity\EntityInterface
+   *   The decorated entity.
+   */
+  public function getEntity() {
+    return $this->subject;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
+    return $this->subject->access($operation, $account, $return_as_object);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheContexts() {
+    return $this->subject->getCacheContexts();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTags() {
+    return $this->subject->getCacheTags();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheMaxAge() {
+    return $this->subject->getCacheMaxAge();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function uuid() {
+    return $this->subject->uuid();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function id() {
+    return $this->subject->id();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function language() {
+    return $this->subject->language();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isNew() {
+    return $this->subject->isNew();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function enforceIsNew($value = TRUE) {
+    $this->subject->enforceIsNew($value);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getEntityTypeId() {
+    return $this->subject->getEntityTypeId();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function bundle() {
+    return $this->subject->bundle();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function label() {
+    return $this->subject->label();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function urlInfo($rel = 'canonical', array $options = []) {
+    return $this->subject->urlInfo($rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function toUrl($rel = 'canonical', array $options = []) {
+    return $this->subject->toUrl($rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function url($rel = 'canonical', $options = []) {
+    return $this->subject->url($rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function link($text = NULL, $rel = 'canonical', array $options = []) {
+    return $this->subject->link($text, $rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function toLink($text = NULL, $rel = 'canonical', array $options = []) {
+    return $this->subject->toLink($text, $rel, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function hasLinkTemplate($key) {
+    return $this->subject->hasLinkTemplate($key);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function uriRelationships() {
+    return $this->subject->uriRelationships();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function load($id) {
+    throw new \LogicException('Static methods cannot be called on the decorated entity');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function loadMultiple(array $ids = NULL) {
+    throw new \LogicException('Static methods cannot be called on the decorated entity');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(array $values = []) {
+    throw new \LogicException('Static methods cannot be called on the decorated entity');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save() {
+    return $this->subject->save();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function delete() {
+    return $this->subject->delete();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preSave(EntityStorageInterface $storage) {
+    $this->subject->preSave($storage);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
+    return $this->subject->postSave($storage, $update);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function preCreate(EntityStorageInterface $storage, array &$values) {
+    throw new \LogicException('Static methods cannot be called on the decorated entity');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function postCreate(EntityStorageInterface $storage) {
+    return $this->subject->postCreate($storage);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function preDelete(EntityStorageInterface $storage, array $entities) {
+    throw new \LogicException('Static methods cannot be called on the decorated entity');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function postDelete(EntityStorageInterface $storage, array $entities) {
+    throw new \LogicException('Static methods cannot be called on the decorated entity');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function postLoad(EntityStorageInterface $storage, array &$entities) {
+    throw new \LogicException('Static methods cannot be called on the decorated entity');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createDuplicate() {
+    return $this->subject->createDuplicate();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getEntityType() {
+    return $this->subject->getEntityType();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function referencedEntities() {
+    return $this->subject->referencedEntities();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getOriginalId() {
+    return $this->subject->getOriginalId();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCacheTagsToInvalidate() {
+    return $this->subject->getCacheTagsToInvalidate();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setOriginalId($id) {
+    $this->subject->setOriginalId($id);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTypedData() {
+    return $this->subject->getTypedData();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfigDependencyKey() {
+    return $this->subject->getConfigDependencyKey();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfigDependencyName() {
+    return $this->subject->getConfigDependencyName();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfigTarget() {
+    return $this->subject->getConfigTarget();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function toArray() {
+    return $this->subject->toArray();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheContexts(array $cache_contexts) {
+    $this->subject->addCacheContexts($cache_contexts);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheTags(array $cache_tags) {
+    $this->subject->addCacheTags($cache_tags);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function mergeCacheMaxAge($max_age) {
+    $this->subject->mergeCacheMaxAge($max_age);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addCacheableDependency($other_object) {
+    $this->subject->addCacheableDependency($other_object);
+    return $this;
+  }
+
+}
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..9241901bb4
--- /dev/null
+++ b/core/modules/layout_builder/src/Entity/LayoutBuilderEntityViewDisplay.php
@@ -0,0 +1,331 @@
+<?php
+
+namespace Drupal\layout_builder\Entity;
+
+use Drupal\Core\Entity\Entity\EntityViewDisplay as BaseEntityViewDisplay;
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\layout_builder\Section;
+
+/**
+ * Provides an entity view display entity that has a layout.
+ */
+class LayoutBuilderEntityViewDisplay extends BaseEntityViewDisplay implements LayoutEntityDisplayInterface {
+
+  /**
+   * {@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() {
+    $sections = [];
+    foreach ($this->getSectionsInfo() as $delta => $info) {
+      $sections[$delta] = $this->getSection($delta);
+    }
+    return $sections;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSection($delta) {
+    return new Section($this->getLayoutId($delta), $this->getLayoutSettings($delta), $this->getLayoutSectionData($delta));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function updateSection($delta, Section $new_section) {
+    $new_layout_id = $new_section->getLayoutId();
+
+    // Instantiate the plugin and consult it for the updated plugin
+    // configuration. Once layouts are no longer stored as third party settings,
+    // this will be handled by the code in
+    // \Drupal\Core\Config\Entity\ConfigEntityBase::set() that handles
+    // \Drupal\Core\Entity\EntityWithPluginCollectionInterface.
+    $new_layout_settings = $this->refreshLayoutSettings($new_layout_id, $new_section->getLayoutSettings());
+
+    $old_section = $this->getSection($delta);
+    $new_section_data = $this->refreshSectionData($old_section->getLayoutId(), $new_layout_id, $new_section->getValue());
+
+    $result = [
+      'layout_id' => $new_layout_id,
+      'layout_settings' => $new_layout_settings,
+      'section_data' => $new_section_data,
+    ];
+    $this->setSectionInfo($delta, $result);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function clearCachedDefinitions() {
+    $this->fieldDefinitions = NULL;
+    return $this;
+  }
+
+  /**
+   * Gets the stored section information.
+   *
+   * @return array
+   *   A sequence of section data, keyed by delta.
+   */
+  protected function getSectionsInfo() {
+    return $this->getThirdPartySetting('layout_builder', 'sections', []);
+  }
+
+  /**
+   * Store the information for all sections.
+   *
+   * @param array $sections
+   *   The sections information.
+   *
+   * @return $this
+   */
+  protected function setSectionsInfo(array $sections) {
+    $this->setThirdPartySetting('layout_builder', 'sections', $sections);
+    return $this;
+  }
+
+  /**
+   * Gets the section information at the specified delta.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   *
+   * @return mixed[]
+   *   An array with three keys:
+   *   - id
+   *   - settings
+   *   - section
+   */
+  protected function getSectionInfo($delta) {
+    $sections = $this->getSectionsInfo();
+    if (!isset($sections[$delta])) {
+      if ($delta === 0) {
+        $sections[$delta] = [];
+      }
+      else {
+        throw new \OutOfBoundsException('Invalid delta');
+      }
+    }
+    $sections[$delta] += [
+      'layout_id' => NULL,
+      'layout_settings' => [],
+      'section_data' => [],
+    ];
+    return $sections[$delta];
+  }
+
+  /**
+   * Store the information for a section.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   * @param array $info
+   *   The array of section info.
+   *
+   * @return $this
+   */
+  protected function setSectionInfo($delta, array $info) {
+    $sections = $this->getSectionsInfo();
+    $sections[$delta] = $info;
+    $this->setSectionsInfo($sections);
+    return $this;
+  }
+
+  /**
+   * Returns the layout ID for a specified delta.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   *
+   * @return string
+   *   The layout ID.
+   */
+  protected function getLayoutId($delta) {
+    return $this->getSectionInfo($delta)['layout_id'];
+  }
+
+  /**
+   * Returns the layout settings for a specified delta.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   *
+   * @return array
+   *   The layout settings.
+   */
+  protected function getLayoutSettings($delta) {
+    return $this->getSectionInfo($delta)['layout_settings'];
+  }
+
+  /**
+   * Returns the section data for a specified delta.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   *
+   * @return array
+   *   The section data.
+   */
+  protected function getLayoutSectionData($delta) {
+    return $this->getSectionInfo($delta)['section_data'];
+  }
+
+  /**
+   * Refreshes the section data to account for the new layout.
+   *
+   * @param string $old_layout_id
+   *   The old layout ID.
+   * @param string $new_layout_id
+   *   The new layout ID.
+   * @param array $section_data
+   *   The current section data.
+   *
+   * @return array
+   *   The updated section data.
+   */
+  protected function refreshSectionData($old_layout_id, $new_layout_id, array $section_data) {
+    if ($old_layout_id !== $new_layout_id) {
+      // @todo Devise a mechanism for mapping old regions to new ones in
+      //   https://www.drupal.org/node/2796877.
+      $layout_definition = $this->getLayoutDefinition($new_layout_id);
+      $new_region = $layout_definition->getDefaultRegion();
+      $layout_regions = $layout_definition->getRegions();
+      foreach ($section_data as $region => $blocks) {
+        if (!isset($layout_regions[$region])) {
+          $section_data[$new_region] = $blocks;
+          unset($section_data[$region]);
+        }
+      }
+    }
+    return $section_data;
+  }
+
+  /**
+   * Refreshes the layout settings to ensure the plugin defaults are up to date.
+   *
+   * @param string $layout_id
+   *   A layout plugin ID.
+   * @param array $layout_settings
+   *   An array of settings.
+   *
+   * @return array
+   *   The updated layout settings.
+   */
+  protected function refreshLayoutSettings($layout_id, array $layout_settings) {
+    return $this->layoutPluginManager()->createInstance($layout_id, $layout_settings)->getConfiguration();
+  }
+
+  /**
+   * 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');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setComponent($name, array $options = []) {
+    parent::setComponent($name, $options);
+
+    if ($this->findComponent($name) === FALSE) {
+      $section = $this->getSection(0);
+      $region = isset($options['region']) ? $options['region'] : $this->getDefaultRegion(0);
+      // @todo Components need to be referenceable as blocks.
+      $section->addBlock($region, $name, ['configuration' => []]);
+      $this->updateSection(0, $section);
+    }
+
+    return $this;
+  }
+
+  /**
+   * Finds the section delta of a given component.
+   *
+   * @param string $name
+   *   The name of the component.
+   *
+   * @return false|int|null
+   *   Either a section delta, FALSE if the component is not found, NULL if the
+   *   component should not be stored.
+   */
+  protected function findComponent($name) {
+    $field_definition = $this->getFieldDefinition($name);
+    if (!$field_definition || !$field_definition->isDisplayConfigurable('view')) {
+      return NULL;
+    }
+
+    foreach ($this->getSections() as $delta => $section) {
+      $blocks = $section->getValue();
+      if (isset($blocks[$name])) {
+        return $delta;
+      }
+    }
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function init() {
+    if (!$this->getLayoutId(0)) {
+      $this->updateSection(0, new Section('layout_onecol'));
+    }
+    parent::init();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preSave(EntityStorageInterface $storage, $update = TRUE) {
+    parent::preSave($storage, $update);
+
+    // 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->updateSection($delta, $section);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getDefaultRegion($delta = 0) {
+    return $this->getLayoutDefinition($this->getLayoutId($delta))->getDefaultRegion();
+  }
+
+}
diff --git a/core/modules/layout_builder/src/Entity/LayoutEntity.php b/core/modules/layout_builder/src/Entity/LayoutEntity.php
new file mode 100644
index 0000000000..65b6ac8b57
--- /dev/null
+++ b/core/modules/layout_builder/src/Entity/LayoutEntity.php
@@ -0,0 +1,233 @@
+<?php
+
+namespace Drupal\layout_builder\Entity;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\FieldableEntityInterface;
+use Drupal\layout_builder\Section;
+
+/**
+ * Decorates an entity.
+ */
+class LayoutEntity extends EntityDecorator {
+
+  /**
+   * The name of the layout field.
+   *
+   * @var string
+   */
+  const FIELD_NAME = 'layout_builder__layout';
+
+  /**
+   * LayoutEntity constructor.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $subject
+   *   The entity being decorated.
+   */
+  public function __construct(EntityInterface $subject) {
+    if ($subject instanceof FieldableEntityInterface || $subject instanceof LayoutEntityDisplayInterface || $subject instanceof LayoutEntity) {
+      parent::__construct($subject);
+    }
+    else {
+      throw new \InvalidArgumentException('Entity not supported');
+    }
+  }
+
+  /**
+   * Checks if this entity supports layouts.
+   *
+   * @return bool
+   *   TRUE if the entity supports layouts, FALSE otherwise.
+   */
+  public function isLayoutEnabled() {
+    if ($this->subject instanceof FieldableEntityInterface) {
+      return $this->subject->hasField(static::FIELD_NAME);
+    }
+
+    if ($this->subject instanceof LayoutEntityDisplayInterface) {
+      return TRUE;
+    }
+  }
+
+  /**
+   * Checks if the layout field has a value.
+   *
+   * @return bool
+   *   TRUE if the layout field does not have a value.
+   */
+  public function isLayoutEmpty() {
+    if (!$this->isLayoutEnabled()) {
+      return TRUE;
+    }
+
+    if ($this->subject instanceof FieldableEntityInterface) {
+      return $this->getSectionFields()->isEmpty();
+    }
+    if ($this->subject instanceof LayoutEntityDisplayInterface) {
+      return empty($this->subject->getSections());
+    }
+  }
+
+  /**
+   * Returns the sections.
+   *
+   * @return \Drupal\layout_builder\Section[]
+   *   An array of sections.
+   */
+  public function getSections() {
+    $sections = [];
+    for ($delta = 0; $delta < $this->getSectionCount(); $delta++) {
+      $sections[$delta] = $this->getSection($delta);
+    }
+    return $sections;
+  }
+
+  /**
+   * Gets a specific section.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   *
+   * @return \Drupal\layout_builder\Section
+   *   The section.
+   */
+  public function getSection($delta) {
+    if ($this->subject instanceof FieldableEntityInterface) {
+      return $this->getSectionField($delta)->getSection();
+    }
+    if ($this->subject instanceof LayoutEntityDisplayInterface) {
+      return $this->subject->getSection($delta);
+    }
+  }
+
+  /**
+   * Updates an existing section.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   * @param \Drupal\layout_builder\Section $section
+   *   The section.
+   *
+   * @return $this
+   */
+  public function updateSection($delta, Section $section) {
+    if ($this->subject instanceof FieldableEntityInterface) {
+      $this->getSectionField($delta)->updateFromSection($section);
+    }
+    if ($this->subject instanceof LayoutEntityDisplayInterface) {
+      $this->subject->updateSection($delta, $section);
+    }
+    return $this;
+  }
+
+  /**
+   * Adds a new section item.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   * @param \Drupal\layout_builder\Section $section
+   *   The section to add.
+   *
+   * @return $this
+   */
+  public function addSection($delta, Section $section) {
+    if ($this->subject instanceof FieldableEntityInterface) {
+      $this->getSectionFields()->addSection($delta, $section);
+    }
+    if ($this->subject instanceof LayoutEntityDisplayInterface) {
+      // @todo Field Layout should support multiple sections.
+      throw new \LogicException('Field Layout currently only supports a single section');
+    }
+    return $this;
+  }
+
+  /**
+   * Removes a specific section item.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   *
+   * @return $this
+   */
+  public function removeSection($delta) {
+    if ($this->subject instanceof FieldableEntityInterface) {
+      $this->getSectionFields()->removeItem($delta);
+    }
+    if ($this->subject instanceof LayoutEntityDisplayInterface) {
+      // @todo Field Layout should support multiple sections.
+      throw new \LogicException('Field Layout currently only supports a single section');
+    }
+    return $this;
+  }
+
+  /**
+   * Appends a new section to the end of the list.
+   *
+   * @param \Drupal\layout_builder\Section $section
+   *   The section to append.
+   *
+   * @return $this
+   */
+  public function appendSection(Section $section) {
+    if ($this->subject instanceof FieldableEntityInterface) {
+      $this->getSectionFields()->appendSection($section);
+    }
+    if ($this->subject instanceof LayoutEntityDisplayInterface) {
+      // @todo Field Layout should support multiple sections.
+      throw new \LogicException('Field Layout currently only supports a single section');
+    }
+    return $this;
+  }
+
+  /**
+   * Gets the layout field list.
+   *
+   * @return \Drupal\layout_builder\Field\LayoutSectionItemListInterface
+   *   The layout field list.
+   */
+  protected function getSectionFields() {
+    if (!$this->subject instanceof FieldableEntityInterface) {
+      throw new \LogicException('Non-fieldable entities are not supported');
+    }
+
+    return $this->subject->get(static::FIELD_NAME);
+  }
+
+  /**
+   * Gets the number of sections.
+   *
+   * @return int
+   *   The number of available sections.
+   */
+  protected function getSectionCount() {
+    if ($this->subject instanceof FieldableEntityInterface) {
+      return $this->getSectionFields()->count();
+    }
+    if ($this->subject instanceof LayoutEntityDisplayInterface) {
+      // @todo Field Layout should support multiple sections.
+      return 1;
+    }
+  }
+
+  /**
+   * Gets the layout section item.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   *
+   * @return \Drupal\layout_builder\Field\LayoutSectionItemInterface
+   *   The layout field.
+   */
+  protected function getSectionField($delta) {
+    if (!$this->subject instanceof FieldableEntityInterface) {
+      throw new \LogicException('Non-fieldable entities are not supported');
+    }
+
+    if ($section_field = $this->getSectionFields()->get($delta)) {
+      return $section_field;
+    }
+
+    throw new \OutOfBoundsException('Invalid delta');
+  }
+
+}
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..1587072e05
--- /dev/null
+++ b/core/modules/layout_builder/src/Entity/LayoutEntityDisplayInterface.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace Drupal\layout_builder\Entity;
+
+use Drupal\Core\Entity\Display\EntityDisplayInterface;
+use Drupal\layout_builder\Section;
+
+/**
+ * Provides an interface for entity displays that have layout.
+ */
+interface LayoutEntityDisplayInterface extends EntityDisplayInterface {
+
+  /**
+   * 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);
+
+  /**
+   * Gets the layout sections.
+   *
+   * @return \Drupal\layout_builder\Section[]
+   *   An array of sections.
+   */
+  public function getSections();
+
+  /**
+   * Gets a domain object for the layout section.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   *
+   * @return \Drupal\layout_builder\Section
+   *   The layout section.
+   */
+  public function getSection($delta);
+
+  /**
+   * Updates the stored value based on the domain object.
+   *
+   * @param int $delta
+   *   The delta of the section.
+   * @param \Drupal\layout_builder\Section $new_section
+   *   The layout section.
+   *
+   * @return $this
+   */
+  public function updateSection($delta, Section $new_section);
+
+  /**
+   * Clears the cached definitions.
+   *
+   * @return $this
+   */
+  public function clearCachedDefinitions();
+
+}
diff --git a/core/modules/layout_builder/src/Field/LayoutSectionItemList.php b/core/modules/layout_builder/src/Field/LayoutSectionItemList.php
index 933ed6eb97..f8c5eb1ae3 100644
--- a/core/modules/layout_builder/src/Field/LayoutSectionItemList.php
+++ b/core/modules/layout_builder/src/Field/LayoutSectionItemList.php
@@ -3,6 +3,7 @@
 namespace Drupal\layout_builder\Field;
 
 use Drupal\Core\Field\FieldItemList;
+use Drupal\layout_builder\Section;
 
 /**
  * Defines a item list class for layout section fields.
@@ -16,7 +17,24 @@ class LayoutSectionItemList extends FieldItemList implements LayoutSectionItemLi
   /**
    * {@inheritdoc}
    */
-  public function addItem($index, $value) {
+  public function appendSection(Section $section) {
+    $this->appendItem([
+      'layout' => $section->getLayoutId(),
+      'layout_settings' => $section->getLayoutSettings(),
+      'section' => $section->getValue(),
+    ]);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function addSection($index, Section $section) {
+    $value = [
+      'layout' => $section->getLayoutId(),
+      'layout_settings' => $section->getLayoutSettings(),
+      'section' => $section->getValue(),
+    ];
     if ($this->get($index)) {
       $start = array_slice($this->list, 0, $index);
       $end = array_slice($this->list, $index);
@@ -24,9 +42,9 @@ public function addItem($index, $value) {
       $this->list = array_merge($start, [$item], $end);
     }
     else {
-      $item = $this->appendItem($value);
+      $this->appendItem($value);
     }
-    return $item;
+    return $this;
   }
 
 }
diff --git a/core/modules/layout_builder/src/Field/LayoutSectionItemListInterface.php b/core/modules/layout_builder/src/Field/LayoutSectionItemListInterface.php
index 81839d1774..89a1897c89 100644
--- a/core/modules/layout_builder/src/Field/LayoutSectionItemListInterface.php
+++ b/core/modules/layout_builder/src/Field/LayoutSectionItemListInterface.php
@@ -3,6 +3,7 @@
 namespace Drupal\layout_builder\Field;
 
 use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\layout_builder\Section;
 
 /**
  * Defines a item list class for layout section fields.
@@ -25,22 +26,28 @@
   public function get($index);
 
   /**
-   * Adds a new item to the list.
+   * Adds a new section at a given delta.
    *
-   * If an item exists at the given index, the item at that position and others
-   * after it are shifted backward.
+   * If a section exists at the given index, the section at that position and
+   * others after it are shifted backward.
    *
-   * @param int $index
-   *   The position of the item in the list.
-   * @param mixed $value
-   *   The value of the item to be stored at the specified position.
+   * @param int $delta
+   *   The delta of the section.
+   * @param \Drupal\layout_builder\Section $section
+   *   The section to add.
    *
-   * @return \Drupal\Core\TypedData\TypedDataInterface
-   *   The item that was appended.
+   * @return $this
+   */
+  public function addSection($delta, Section $section);
+
+  /**
+   * Appends a new section to the end of the list.
+   *
+   * @param \Drupal\layout_builder\Section $section
+   *   The section to append.
    *
-   * @todo Move to \Drupal\Core\TypedData\ListInterface directly in
-   *   https://www.drupal.org/node/2907417.
+   * @return $this
    */
-  public function addItem($index, $value);
+  public function appendSection(Section $section);
 
 }
diff --git a/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php b/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
index 7356ef4ccd..70ae95ceae 100644
--- a/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
+++ b/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
@@ -6,7 +6,6 @@
 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;
@@ -16,6 +15,7 @@
 use Drupal\Core\Plugin\PluginFormFactoryInterface;
 use Drupal\Core\Plugin\PluginWithFormsInterface;
 use Drupal\layout_builder\Controller\LayoutRebuildTrait;
+use Drupal\layout_builder\Entity\LayoutEntity;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Drupal\layout_builder\Section;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -90,7 +90,7 @@
   /**
    * The entity.
    *
-   * @var \Drupal\Core\Entity\EntityInterface
+   * @var \Drupal\layout_builder\Entity\LayoutEntity
    */
   protected $entity;
 
@@ -159,7 +159,7 @@ 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
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity being configured.
    * @param int $delta
    *   The delta of the section.
@@ -173,7 +173,7 @@ 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 = []) {
+  public function buildForm(array $form, FormStateInterface $form_state, LayoutEntity $entity = NULL, $delta = NULL, $region = NULL, $plugin_id = NULL, array $configuration = []) {
     $this->entity = $entity;
     $this->delta = $delta;
     $this->region = $region;
@@ -246,11 +246,9 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
 
     $configuration = $this->block->getConfiguration();
 
-    /** @var \Drupal\layout_builder\Field\LayoutSectionItemInterface $field */
-    $field = $this->entity->layout_builder__layout->get($this->delta);
-    $section = $field->getSection();
-    $this->submitBlock($section, $this->region, $configuration['uuid'], ['block' => $configuration]);
-    $field->updateFromSection($section);
+    $section = $this->entity->getSection($this->delta);
+    $this->submitBlock($section, $this->region, $configuration['uuid'], ['configuration' => $configuration]);
+    $this->entity->updateSection($this->delta, $section);
 
     $this->layoutTempstoreRepository->set($this->entity);
     $form_state->setRedirectUrl($this->entity->toUrl('layout-builder'));
diff --git a/core/modules/layout_builder/src/Form/ConfigureSectionForm.php b/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
index 17913237d5..ff378ece06 100644
--- a/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
+++ b/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
@@ -3,17 +3,17 @@
 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;
 use Drupal\Core\Layout\LayoutInterface;
-use Drupal\Core\Layout\LayoutPluginManagerInterface;
 use Drupal\Core\Plugin\PluginFormFactoryInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
 use Drupal\Core\Plugin\PluginWithFormsInterface;
 use Drupal\layout_builder\Controller\LayoutRebuildTrait;
+use Drupal\layout_builder\Entity\LayoutEntity;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
+use Drupal\layout_builder\Section;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -40,13 +40,6 @@ class ConfigureSectionForm extends FormBase {
    */
   protected $layout;
 
-  /**
-   * The layout manager.
-   *
-   * @var \Drupal\Core\Layout\LayoutPluginManagerInterface
-   */
-  protected $layoutManager;
-
   /**
    * The plugin form manager.
    *
@@ -57,7 +50,7 @@ class ConfigureSectionForm extends FormBase {
   /**
    * The entity.
    *
-   * @var \Drupal\Core\Entity\EntityInterface
+   * @var \Drupal\layout_builder\Entity\LayoutEntity
    */
   protected $entity;
 
@@ -80,16 +73,13 @@ class ConfigureSectionForm extends FormBase {
    *
    * @param \Drupal\layout_builder\LayoutTempstoreRepositoryInterface $layout_tempstore_repository
    *   The layout tempstore repository.
-   * @param \Drupal\Core\Layout\LayoutPluginManagerInterface $layout_manager
-   *   The layout manager.
    * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
    *   The class resolver.
    * @param \Drupal\Core\Plugin\PluginFormFactoryInterface $plugin_form_manager
    *   The plugin form manager.
    */
-  public function __construct(LayoutTempstoreRepositoryInterface $layout_tempstore_repository, LayoutPluginManagerInterface $layout_manager, ClassResolverInterface $class_resolver, PluginFormFactoryInterface $plugin_form_manager) {
+  public function __construct(LayoutTempstoreRepositoryInterface $layout_tempstore_repository, ClassResolverInterface $class_resolver, PluginFormFactoryInterface $plugin_form_manager) {
     $this->layoutTempstoreRepository = $layout_tempstore_repository;
-    $this->layoutManager = $layout_manager;
     $this->classResolver = $class_resolver;
     $this->pluginFormFactory = $plugin_form_manager;
   }
@@ -100,7 +90,6 @@ public function __construct(LayoutTempstoreRepositoryInterface $layout_tempstore
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('layout_builder.tempstore_repository'),
-      $container->get('plugin.manager.core.layout'),
       $container->get('class_resolver'),
       $container->get('plugin_form.factory')
     );
@@ -116,19 +105,18 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $entity = NULL, $delta = NULL, $plugin_id = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, LayoutEntity $entity = NULL, $delta = NULL, $plugin_id = NULL) {
     $this->entity = $entity;
     $this->delta = $delta;
     $this->isUpdate = is_null($plugin_id);
 
-    $configuration = [];
     if ($this->isUpdate) {
-      /** @var \Drupal\layout_builder\Field\LayoutSectionItemInterface $field */
-      $field = $this->entity->layout_builder__layout->get($this->delta);
-      $plugin_id = $field->layout;
-      $configuration = $field->layout_settings;
+      $section = $this->entity->getSection($this->delta);
     }
-    $this->layout = $this->layoutManager->createInstance($plugin_id, $configuration);
+    else {
+      $section = new Section($plugin_id);
+    }
+    $this->layout = $section->getLayout();
 
     $form['#tree'] = TRUE;
     $form['layout_settings'] = [];
@@ -166,19 +154,14 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
     $plugin_id = $this->layout->getPluginId();
     $configuration = $this->layout->getConfiguration();
 
-    /** @var \Drupal\layout_builder\Field\LayoutSectionItemListInterface $field_list */
-    $field_list = $this->entity->layout_builder__layout;
     if ($this->isUpdate) {
-      $field = $field_list->get($this->delta);
-      $field->layout = $plugin_id;
-      $field->layout_settings = $configuration;
+      $section = $this->entity->getSection($this->delta);
+      $section->setLayoutId($plugin_id);
+      $section->setLayoutSettings($configuration);
+      $this->entity->updateSection($this->delta, $section);
     }
     else {
-      $field_list->addItem($this->delta, [
-        'layout' => $plugin_id,
-        'layout_settings' => $configuration,
-        'section' => [],
-      ]);
+      $this->entity->addSection($this->delta, new Section($plugin_id, $configuration));
     }
 
     $this->layoutTempstoreRepository->set($this->entity);
diff --git a/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php b/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
index 8bee062d4e..2b5912e50e 100644
--- a/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
+++ b/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
@@ -3,10 +3,10 @@
 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\Entity\LayoutEntity;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -30,7 +30,7 @@
   /**
    * The entity.
    *
-   * @var \Drupal\Core\Entity\EntityInterface
+   * @var \Drupal\layout_builder\Entity\LayoutEntity
    */
   protected $entity;
 
@@ -74,7 +74,7 @@ public function getCancelUrl() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, EntityInterface $entity = NULL, $delta = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, LayoutEntity $entity = NULL, $delta = NULL) {
     $this->entity = $entity;
     $this->delta = $delta;
 
@@ -109,11 +109,11 @@ protected function successfulAjaxSubmit(array $form, FormStateInterface $form_st
   /**
    * Performs any actions on the layout entity before saving.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity.
    * @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 handleEntity(LayoutEntity $entity, FormStateInterface $form_state);
 
 }
diff --git a/core/modules/layout_builder/src/Form/RemoveBlockForm.php b/core/modules/layout_builder/src/Form/RemoveBlockForm.php
index 139186af66..446a1a98b7 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\Entity\LayoutEntity;
 
 /**
  * Provides a form to confirm the removal of a block.
@@ -50,7 +50,7 @@ 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, LayoutEntity $entity = NULL, $delta = NULL, $region = NULL, $uuid = NULL) {
     $this->region = $region;
     $this->uuid = $uuid;
     return parent::buildForm($form, $form_state, $entity, $delta);
@@ -59,12 +59,10 @@ public function buildForm(array $form, FormStateInterface $form_state, EntityInt
   /**
    * {@inheritdoc}
    */
-  protected function handleEntity(EntityInterface $entity, FormStateInterface $form_state) {
-    /** @var \Drupal\layout_builder\Field\LayoutSectionItemInterface $field */
-    $field = $entity->layout_builder__layout->get($this->delta);
-    $section = $field->getSection();
-    $section->removeBlock($this->region, $this->uuid);
-    $field->updateFromSection($section);
+  protected function handleEntity(LayoutEntity $entity, FormStateInterface $form_state) {
+    $section = $entity->getSection($this->delta);
+    $section->removeBlock($this->uuid);
+    $entity->updateSection($this->delta, $section);
   }
 
 }
diff --git a/core/modules/layout_builder/src/Form/RemoveSectionForm.php b/core/modules/layout_builder/src/Form/RemoveSectionForm.php
index e44edd6947..45adf14be0 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\Entity\LayoutEntity;
 
 /**
  * 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 handleEntity(LayoutEntity $entity, FormStateInterface $form_state) {
+    $entity->removeSection($this->delta);
   }
 
 }
diff --git a/core/modules/layout_builder/src/Form/UpdateBlockForm.php b/core/modules/layout_builder/src/Form/UpdateBlockForm.php
index 2f2aa600e4..6e28de9579 100644
--- a/core/modules/layout_builder/src/Form/UpdateBlockForm.php
+++ b/core/modules/layout_builder/src/Form/UpdateBlockForm.php
@@ -2,8 +2,8 @@
 
 namespace Drupal\layout_builder\Form;
 
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\layout_builder\Entity\LayoutEntity;
 use Drupal\layout_builder\Section;
 
 /**
@@ -27,7 +27,7 @@ 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
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity being configured.
    * @param int $delta
    *   The delta of the section.
@@ -39,15 +39,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) {
-    /** @var \Drupal\layout_builder\Field\LayoutSectionItemInterface $field */
-    $field = $entity->layout_builder__layout->get($delta);
-    $block = $field->getSection()->getBlock($region, $uuid);
-    if (empty($block['block']['id'])) {
+  public function buildForm(array $form, FormStateInterface $form_state, LayoutEntity $entity = NULL, $delta = NULL, $region = NULL, $uuid = NULL) {
+    $block = $entity->getSection($delta)->getBlock($uuid);
+    if (empty($block['configuration']['id'])) {
       throw new \InvalidArgumentException('Invalid UUID specified');
     }
 
-    return parent::buildForm($form, $form_state, $entity, $delta, $region, $block['block']['id'], $block['block']);
+    return parent::buildForm($form, $form_state, $entity, $delta, $region, $block['configuration']['id'], $block['configuration']);
   }
 
   /**
diff --git a/core/modules/layout_builder/src/LayoutSectionBuilder.php b/core/modules/layout_builder/src/LayoutSectionBuilder.php
index 1682974f11..509b4d85de 100644
--- a/core/modules/layout_builder/src/LayoutSectionBuilder.php
+++ b/core/modules/layout_builder/src/LayoutSectionBuilder.php
@@ -5,13 +5,10 @@
 use Drupal\Component\Plugin\Exception\PluginException;
 use Drupal\Core\Block\BlockManagerInterface;
 use Drupal\Core\Cache\CacheableMetadata;
-use Drupal\Core\Layout\LayoutInterface;
-use Drupal\Core\Layout\LayoutPluginManagerInterface;
 use Drupal\Core\Plugin\Context\ContextHandlerInterface;
 use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
 use Drupal\Core\Plugin\ContextAwarePluginInterface;
 use Drupal\Core\Session\AccountInterface;
-use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
  * Builds the UI for layout sections.
@@ -20,8 +17,6 @@
  */
 class LayoutSectionBuilder {
 
-  use StringTranslationTrait;
-
   /**
    * The current user.
    *
@@ -29,13 +24,6 @@ class LayoutSectionBuilder {
    */
   protected $account;
 
-  /**
-   * The layout plugin manager.
-   *
-   * @var \Drupal\Core\Layout\LayoutPluginManagerInterface
-   */
-  protected $layoutPluginManager;
-
   /**
    * The block plugin manager.
    *
@@ -62,8 +50,6 @@ class LayoutSectionBuilder {
    *
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The current user.
-   * @param \Drupal\Core\Layout\LayoutPluginManagerInterface $layoutPluginManager
-   *   The layout plugin manager.
    * @param \Drupal\Core\Block\BlockManagerInterface $blockManager
    *   THe block plugin manager.
    * @param \Drupal\Core\Plugin\Context\ContextHandlerInterface $context_handler
@@ -71,9 +57,8 @@ class LayoutSectionBuilder {
    * @param \Drupal\Core\Plugin\Context\ContextRepositoryInterface $context_repository
    *   The lazy context repository service.
    */
-  public function __construct(AccountInterface $account, LayoutPluginManagerInterface $layoutPluginManager, BlockManagerInterface $blockManager, ContextHandlerInterface $context_handler, ContextRepositoryInterface $context_repository) {
+  public function __construct(AccountInterface $account, BlockManagerInterface $blockManager, ContextHandlerInterface $context_handler, ContextRepositoryInterface $context_repository) {
     $this->account = $account;
-    $this->layoutPluginManager = $layoutPluginManager;
     $this->blockManager = $blockManager;
     $this->contextHandler = $context_handler;
     $this->contextRepository = $context_repository;
@@ -82,33 +67,24 @@ public function __construct(AccountInterface $account, LayoutPluginManagerInterf
   /**
    * Builds the render array for the layout section.
    *
-   * @param \Drupal\Core\Layout\LayoutInterface $layout
-   *   The ID of the layout.
-   * @param array $section
-   *   An array of configuration, keyed first by region and then by block UUID.
+   * @param \Drupal\layout_builder\Section $section
+   *   The layout section.
    *
    * @return array
    *   The render array for a given section.
    */
-  public function buildSectionFromLayout(LayoutInterface $layout, array $section) {
+  public function buildSection(Section $section) {
+    $layout = $section->getLayout();
     $cacheability = CacheableMetadata::createFromRenderArray([]);
 
-    $regions = [];
+    // Add the regions to the $build in the correct order.
+    $regions = array_fill_keys($layout->getPluginDefinition()->getRegionNames(), []);
+
     $weight = 0;
-    foreach ($section as $region => $blocks) {
-      if (!is_array($blocks)) {
-        throw new \InvalidArgumentException(sprintf('The "%s" region in the "%s" layout has invalid configuration', $region, $layout->getPluginId()));
-      }
-
-      foreach ($blocks as $uuid => $configuration) {
-        if (!is_array($configuration) || !isset($configuration['block'])) {
-          throw new \InvalidArgumentException(sprintf('The block with UUID of "%s" has invalid configuration', $uuid));
-        }
-
-        if ($block_output = $this->buildBlock($uuid, $configuration['block'], $cacheability)) {
-          $block_output['#weight'] = $weight++;
-          $regions[$region][$uuid] = $block_output;
-        }
+    foreach ($section->getValue() as $uuid => $block) {
+      if ($block_output = $this->buildBlock($uuid, $block['configuration'], $cacheability)) {
+        $block_output['#weight'] = $weight++;
+        $regions[$block['region']][$uuid] = $block_output;
       }
     }
 
@@ -118,21 +94,32 @@ public function buildSectionFromLayout(LayoutInterface $layout, array $section)
   }
 
   /**
-   * Builds the render array for the layout section.
+   * Alters the existing build based on sections.
    *
-   * @param string $layout_id
-   *   The ID of the layout.
-   * @param array $layout_settings
-   *   The configuration for the layout.
-   * @param array $section
-   *   An array of configuration, keyed first by region and then by block UUID.
-   *
-   * @return array
-   *   The render array for a given section.
+   * @param array $build
+   *   A renderable array representing the entity content.
+   * @param int $delta
+   *   The delta of the section.
+   * @param \Drupal\layout_builder\Section $section
+   *   The section.
    */
-  public function buildSection($layout_id, array $layout_settings, array $section) {
-    $layout = $this->layoutPluginManager->createInstance($layout_id, $layout_settings);
-    return $this->buildSectionFromLayout($layout, $section);
+  public function alterBuild(array &$build, $delta, Section $section) {
+    $layout = $section->getLayout();
+
+    // Add the regions to the $build in the correct order.
+    $regions = array_fill_keys($layout->getPluginDefinition()->getRegionNames(), []);
+    $field_moved = FALSE;
+    foreach ($section->getValue() as $name => $field) {
+      $region = $field['region'];
+      if (isset($regions[$region]) && isset($build[$name])) {
+        $regions[$region][$name] = $build[$name];
+        unset($build[$name]);
+        $field_moved = TRUE;
+      }
+    }
+    if ($field_moved) {
+      $build['_layout_builder'][$delta] = $layout->build($regions);
+    }
   }
 
   /**
diff --git a/core/modules/layout_builder/src/LayoutTempstoreRepository.php b/core/modules/layout_builder/src/LayoutTempstoreRepository.php
index 87baa1331c..9582d83ca2 100644
--- a/core/modules/layout_builder/src/LayoutTempstoreRepository.php
+++ b/core/modules/layout_builder/src/LayoutTempstoreRepository.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Entity\RevisionableInterface;
+use Drupal\layout_builder\Entity\LayoutEntity;
 use Drupal\user\SharedTempStoreFactory;
 
 /**
@@ -44,7 +45,7 @@ public function __construct(SharedTempStoreFactory $temp_store_factory, EntityTy
   /**
    * {@inheritdoc}
    */
-  public function get(EntityInterface $entity) {
+  public function get(LayoutEntity $entity) {
     $id = $this->generateTempstoreId($entity);
     $tempstore = $this->getTempstore($entity)->get($id);
     if (!empty($tempstore['entity'])) {
@@ -55,6 +56,9 @@ public function get(EntityInterface $entity) {
         throw new \UnexpectedValueException(sprintf('The entry with entity type "%s" and ID "%s" is not a valid entity', $entity_type_id, $id));
       }
     }
+    if (!($entity instanceof LayoutEntity)) {
+      $entity = new LayoutEntity($entity);
+    }
     return $entity;
   }
 
@@ -63,13 +67,13 @@ public function get(EntityInterface $entity) {
    */
   public function getFromId($entity_type_id, $entity_id) {
     $entity = $this->entityTypeManager->getStorage($entity_type_id)->loadRevision($entity_id);
-    return $this->get($entity);
+    return $this->get(new LayoutEntity($entity));
   }
 
   /**
    * {@inheritdoc}
    */
-  public function set(EntityInterface $entity) {
+  public function set(LayoutEntity $entity) {
     $id = $this->generateTempstoreId($entity);
     $this->getTempstore($entity)->set($id, ['entity' => $entity]);
   }
@@ -77,7 +81,7 @@ public function set(EntityInterface $entity) {
   /**
    * {@inheritdoc}
    */
-  public function delete(EntityInterface $entity) {
+  public function delete(LayoutEntity $entity) {
     if ($this->get($entity)) {
       $id = $this->generateTempstoreId($entity);
       $this->getTempstore($entity)->delete($id);
@@ -87,13 +91,14 @@ public function delete(EntityInterface $entity) {
   /**
    * Generates an ID for putting an entity in tempstore.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity being stored.
    *
    * @return string
    *   The tempstore ID.
    */
-  protected function generateTempstoreId(EntityInterface $entity) {
+  protected function generateTempstoreId(LayoutEntity $entity) {
+    $entity = $entity->getEntity();
     $id = "{$entity->id()}.{$entity->language()->getId()}";
     if ($entity instanceof RevisionableInterface) {
       $id .= '.' . $entity->getRevisionId();
@@ -104,13 +109,13 @@ protected function generateTempstoreId(EntityInterface $entity) {
   /**
    * Gets the shared tempstore.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity being stored.
    *
    * @return \Drupal\user\SharedTempStore
    *   The tempstore.
    */
-  protected function getTempstore(EntityInterface $entity) {
+  protected function getTempstore(LayoutEntity $entity) {
     $collection = $entity->getEntityTypeId() . '.layout_builder__layout';
     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..15da8bf8bb 100644
--- a/core/modules/layout_builder/src/LayoutTempstoreRepositoryInterface.php
+++ b/core/modules/layout_builder/src/LayoutTempstoreRepositoryInterface.php
@@ -2,7 +2,7 @@
 
 namespace Drupal\layout_builder;
 
-use Drupal\Core\Entity\EntityInterface;
+use Drupal\layout_builder\Entity\LayoutEntity;
 
 /**
  * Provides an interface for loading layouts from tempstore.
@@ -17,17 +17,17 @@
   /**
    * Gets the tempstore version of an entity, if it exists.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity to check for in tempstore.
    *
-   * @return \Drupal\Core\Entity\EntityInterface
+   * @return \Drupal\layout_builder\Entity\LayoutEntity
    *   Either the version of this entity from tempstore, or the passed entity if
    *   none exists.
    *
    * @throw \UnexpectedValueException
    *   Thrown if a value exists, but is not an entity.
    */
-  public function get(EntityInterface $entity);
+  public function get(LayoutEntity $entity);
 
   /**
    * Loads an entity from tempstore given the entity ID.
@@ -37,7 +37,7 @@ public function get(EntityInterface $entity);
    * @param string $entity_id
    *   The entity ID (or revision ID).
    *
-   * @return \Drupal\Core\Entity\EntityInterface
+   * @return \Drupal\layout_builder\Entity\LayoutEntity
    *   Either the version of this entity from tempstore, or the entity from
    *   storage if none exists.
    *
@@ -49,17 +49,17 @@ public function getFromId($entity_type_id, $entity_id);
   /**
    * Stores this entity in tempstore.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity to set in tempstore.
    */
-  public function set(EntityInterface $entity);
+  public function set(LayoutEntity $entity);
 
   /**
    * Removes the tempstore version of an entity.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $entity
+   * @param \Drupal\layout_builder\Entity\LayoutEntity $entity
    *   The entity to remove from tempstore.
    */
-  public function delete(EntityInterface $entity);
+  public function delete(LayoutEntity $entity);
 
 }
diff --git a/core/modules/layout_builder/src/Plugin/Field/FieldFormatter/LayoutSectionFormatter.php b/core/modules/layout_builder/src/Plugin/Field/FieldFormatter/LayoutSectionFormatter.php
index 4951d01c4b..0cb27f74b6 100644
--- a/core/modules/layout_builder/src/Plugin/Field/FieldFormatter/LayoutSectionFormatter.php
+++ b/core/modules/layout_builder/src/Plugin/Field/FieldFormatter/LayoutSectionFormatter.php
@@ -80,7 +80,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) {
 
     /** @var \Drupal\layout_builder\Field\LayoutSectionItemInterface[] $items */
     foreach ($items as $delta => $item) {
-      $elements[$delta] = $this->builder->buildSection($item->layout, $item->layout_settings, $item->section);
+      $elements[$delta] = $this->builder->buildSection($item->getSection());
     }
 
     return $elements;
diff --git a/core/modules/layout_builder/src/Plugin/Field/FieldType/LayoutSectionItem.php b/core/modules/layout_builder/src/Plugin/Field/FieldType/LayoutSectionItem.php
index fc1c63413f..b83f093f8c 100644
--- a/core/modules/layout_builder/src/Plugin/Field/FieldType/LayoutSectionItem.php
+++ b/core/modules/layout_builder/src/Plugin/Field/FieldType/LayoutSectionItem.php
@@ -118,13 +118,15 @@ public function isEmpty() {
    * {@inheritdoc}
    */
   public function getSection() {
-    return new Section($this->section);
+    return new Section($this->layout, $this->layout_settings, $this->section);
   }
 
   /**
    * {@inheritdoc}
    */
   public function updateFromSection(Section $section) {
+    $this->layout = $section->getLayoutId();
+    $this->layout_settings = $section->getLayoutSettings();
     $this->section = $section->getValue();
     return $this;
   }
diff --git a/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php b/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php
index a1d5fc9140..48b5908d98 100644
--- a/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php
+++ b/core/modules/layout_builder/src/Routing/LayoutTempstoreParamConverter.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\ParamConverter\EntityConverter;
 use Drupal\Core\ParamConverter\ParamConverterInterface;
+use Drupal\layout_builder\Entity\LayoutEntity;
 use Drupal\layout_builder\LayoutTempstoreRepositoryInterface;
 use Symfony\Component\Routing\Route;
 
@@ -40,7 +41,7 @@ public function __construct(EntityManagerInterface $entity_manager, LayoutTempst
    */
   public function convert($value, $definition, $name, array $defaults) {
     if ($entity = parent::convert($value, $definition, $name, $defaults)) {
-      return $this->layoutTempstoreRepository->get($entity);
+      return $this->layoutTempstoreRepository->get(new LayoutEntity($entity));
     }
   }
 
diff --git a/core/modules/layout_builder/src/Section.php b/core/modules/layout_builder/src/Section.php
index f5e19003b5..c9edaaaaec 100644
--- a/core/modules/layout_builder/src/Section.php
+++ b/core/modules/layout_builder/src/Section.php
@@ -5,26 +5,114 @@
 /**
  * Provides a domain object for layout sections.
  *
- * A section is a multi-dimensional array, keyed first by region machine name,
- * then by block UUID, containing block configuration values.
+ * A section consists of three parts:
+ * - A layout plugin ID
+ * - An array of settings for the layout plugin
+ * - A multi-dimensional array of data, keyed first by region machine name, then
+ *   by block UUID, containing block configuration values.
  */
 class Section {
 
+  /**
+   * The layout plugin ID.
+   *
+   * @var string
+   */
+  protected $layoutId;
+
+  /**
+   * The layout plugin settings.
+   *
+   * @var array
+   */
+  protected $layoutSettings;
+
   /**
    * The section data.
    *
    * @var array
    */
-  protected $section;
+  protected $section = [];
 
   /**
    * Constructs a new Section.
    *
+   * @param string $layout_id
+   *   The layout plugin ID.
+   * @param array $layout_settings
+   *   The layout plugin settings.
    * @param array $section
    *   The section data.
    */
-  public function __construct(array $section) {
-    $this->section = $section;
+  public function __construct($layout_id, array $layout_settings = [], array $section = []) {
+    $this->layoutId = $layout_id;
+    $this->layoutSettings = $layout_settings;
+
+    foreach ($section as $uuid => $configuration) {
+      $this->validateBlock($uuid, $configuration);
+      if (isset($configuration['weight'])) {
+        $this->setBlock($configuration['region'], $uuid, $configuration, $configuration['weight']);
+      }
+      else {
+        $this->addBlock($configuration['region'], $uuid, $configuration);
+      }
+    }
+  }
+
+  /**
+   * Gets the layout plugin for this section.
+   *
+   * @return \Drupal\Core\Layout\LayoutInterface
+   *   The layout plugin.
+   */
+  public function getLayout() {
+    return \Drupal::service('plugin.manager.core.layout')->createInstance($this->getLayoutId(), $this->getLayoutSettings());
+  }
+
+  /**
+   * Gets the layout plugin ID for this section.
+   *
+   * @return string
+   *   The layout plugin ID.
+   */
+  public function getLayoutId() {
+    return $this->layoutId;
+  }
+
+  /**
+   * Sets the layout plugin ID for this section.
+   *
+   * @param string $layout_id
+   *   The layout plugin ID.
+   *
+   * @return $this
+   */
+  public function setLayoutId($layout_id) {
+    $this->layoutId = $layout_id;
+    return $this;
+  }
+
+  /**
+   * Gets the layout plugin settings for this section.
+   *
+   * @return mixed[]
+   *   The layout plugin settings.
+   */
+  public function getLayoutSettings() {
+    return $this->layoutSettings;
+  }
+
+  /**
+   * Sets the layout plugin settings for this section.
+   *
+   * @param array $layout_settings
+   *   The layout plugin settings.
+   *
+   * @return $this
+   */
+  public function setLayoutSettings(array $layout_settings) {
+    $this->layoutSettings = $layout_settings;
+    return $this;
   }
 
   /**
@@ -38,10 +126,8 @@ public function getValue() {
   }
 
   /**
-   * Gets the configuration of a given block from a region.
+   * Gets the configuration of a given block.
    *
-   * @param string $region
-   *   The region name.
    * @param string $uuid
    *   The UUID of the block to retrieve.
    *
@@ -49,18 +135,38 @@ public function getValue() {
    *   The block configuration.
    *
    * @throws \InvalidArgumentException
-   *   Thrown when the expected region or UUID do not exist.
+   *   Thrown when the expected UUID does not exist.
    */
-  public function getBlock($region, $uuid) {
-    if (!isset($this->section[$region])) {
-      throw new \InvalidArgumentException('Invalid region');
-    }
-
-    if (!isset($this->section[$region][$uuid])) {
+  public function getBlock($uuid) {
+    if (!isset($this->section[$uuid])) {
       throw new \InvalidArgumentException('Invalid UUID');
     }
 
-    return $this->section[$region][$uuid];
+    return $this->section[$uuid];
+  }
+
+  /**
+   * Validates a given block.
+   *
+   * @param string $uuid
+   *   The UUID of the block to validate.
+   * @param array $block
+   *   The block to validate.
+   *
+   * @return $this
+   *
+   * @throws \InvalidArgumentException
+   *   Thrown when the block values are invalid.
+   */
+  protected function validateBlock($uuid, array $block) {
+    if (!isset($block['region'])) {
+      throw new \InvalidArgumentException(sprintf('The block with UUID of "%s" is missing a region', $uuid));
+    }
+    if (!isset($block['configuration'])) {
+      throw new \InvalidArgumentException(sprintf('The block with UUID of "%s" is missing configuration', $uuid));
+    }
+
+    return $this;
   }
 
   /**
@@ -79,15 +185,37 @@ public function getBlock($region, $uuid) {
    *   Thrown when the expected region or UUID do not exist.
    */
   public function updateBlock($region, $uuid, array $configuration) {
-    if (!isset($this->section[$region])) {
-      throw new \InvalidArgumentException('Invalid region');
-    }
+    $existing_block = $this->getBlock($uuid);
 
-    if (!isset($this->section[$region][$uuid])) {
-      throw new \InvalidArgumentException('Invalid UUID');
-    }
+    $this->setBlock($region, $uuid, $configuration, $existing_block['weight']);
 
-    $this->section[$region][$uuid] = $configuration;
+    return $this;
+  }
+
+  /**
+   * Sets the configuration of a given block for a region.
+   *
+   * @param string $region
+   *   The region name.
+   * @param string $uuid
+   *   The UUID of the block to retrieve.
+   * @param array $configuration
+   *   The block configuration.
+   * @param int $weight
+   *   The weight of the block.
+   *
+   * @return $this
+   */
+  protected function setBlock($region, $uuid, array $configuration, $weight) {
+    $configuration['region'] = $region;
+    $configuration['weight'] = $weight;
+    $this->section[$uuid] = $configuration;
+
+    $this->validateBlock($uuid, $this->section[$uuid]);
+
+    uasort($this->section, function ($a, $b) {
+      return $a['weight'] > $b['weight'] ? 1 : -1;
+    });
 
     return $this;
   }
@@ -95,16 +223,13 @@ public function updateBlock($region, $uuid, array $configuration) {
   /**
    * Removes a given block from a region.
    *
-   * @param string $region
-   *   The region name.
    * @param string $uuid
    *   The UUID of the block to remove.
    *
    * @return $this
    */
-  public function removeBlock($region, $uuid) {
-    unset($this->section[$region][$uuid]);
-    $this->section = array_filter($this->section);
+  public function removeBlock($uuid) {
+    unset($this->section[$uuid]);
     return $this;
   }
 
@@ -121,11 +246,40 @@ public function removeBlock($region, $uuid) {
    * @return $this
    */
   public function addBlock($region, $uuid, array $configuration) {
-    $this->section += [$region => []];
-    $this->section[$region] = array_merge([$uuid => $configuration], $this->section[$region]);
+    $this->setBlock($region, $uuid, $configuration, $this->getNextHighestWeight($region));
     return $this;
   }
 
+  /**
+   * Returns the next highest weight of the blocks in a region.
+   *
+   * @param string $region
+   *   The region name.
+   *
+   * @return int
+   *   A number higher than the highest weight of the blocks in the region.
+   */
+  protected function getNextHighestWeight($region) {
+    $blocks = $this->getBlocksByRegion($region);
+    $weights = array_column($blocks, 'weight');
+    return $weights ? max($weights) + 1 : 0;
+  }
+
+  /**
+   * Gets the blocks for a specific region.
+   *
+   * @param string $region
+   *   The region name.
+   *
+   * @return array
+   *   An array of block info.
+   */
+  protected function getBlocksByRegion($region) {
+    return array_filter($this->section, function ($block) use ($region) {
+      return $block['region'] === $region;
+    });
+  }
+
   /**
    * Inserts a block after a specified existing block in a region.
    *
@@ -144,18 +298,24 @@ public function addBlock($region, $uuid, array $configuration) {
    *   Thrown when the expected region does not exist.
    */
   public function insertBlock($region, $uuid, array $configuration, $preceding_uuid) {
-    if (!isset($this->section[$region])) {
-      throw new \InvalidArgumentException('Invalid region');
-    }
-
-    $slice_id = array_search($preceding_uuid, array_keys($this->section[$region]));
+    $blocks = $this->getBlocksByRegion($region);
+    $slice_id = array_search($preceding_uuid, array_keys($blocks), TRUE);
     if ($slice_id === FALSE) {
       throw new \InvalidArgumentException('Invalid preceding UUID');
     }
 
-    $before = array_slice($this->section[$region], 0, $slice_id + 1);
-    $after = array_slice($this->section[$region], $slice_id + 1);
-    $this->section[$region] = array_merge($before, [$uuid => $configuration], $after);
+    $blocks = [$uuid => $configuration] + array_slice($blocks, $slice_id + 1);
+
+    $existing_block = $this->getBlock($preceding_uuid);
+    if ($existing_block['region'] !== $region) {
+      throw new \InvalidArgumentException('Invalid UUID');
+    }
+
+    $new_weight = $existing_block['weight'] + 1;
+
+    foreach ($blocks as $uuid => $block) {
+      $this->setBlock($region, $uuid, $block, $new_weight++);
+    }
     return $this;
   }
 
diff --git a/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php b/core/modules/layout_builder/tests/src/Functional/LayoutSectionTest.php
index 61e481c7c7..0866dca2e1 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\Tests\BrowserTestBase;
 
 /**
@@ -39,8 +39,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([
@@ -58,15 +58,14 @@ public function providerTestLayoutSectionFormatter() {
         [
           'layout' => 'layout_onecol',
           'section' => [
-            'content' => [
-              'baz' => [
-                'block' => [
-                  'id' => 'test_context_aware',
-                  'context_mapping' => [
-                    'user' => '@user.current_user_context:current_user',
-                  ],
+            'baz' => [
+              'configuration' => [
+                'id' => 'test_context_aware',
+                'context_mapping' => [
+                  'user' => '@user.current_user_context:current_user',
                 ],
               ],
+              'region' => 'content',
             ],
           ],
         ],
@@ -88,12 +87,11 @@ public function providerTestLayoutSectionFormatter() {
         [
           'layout' => 'layout_onecol',
           'section' => [
-            'content' => [
-              'baz' => [
-                'block' => [
-                  'id' => 'system_powered_by_block',
-                ],
+            'baz' => [
+              'configuration' => [
+                'id' => 'system_powered_by_block',
               ],
+              'region' => 'content',
             ],
           ],
         ],
@@ -109,33 +107,30 @@ public function providerTestLayoutSectionFormatter() {
         [
           'layout' => 'layout_onecol',
           'section' => [
-            'content' => [
-              'baz' => [
-                'block' => [
-                  'id' => 'system_powered_by_block',
-                ],
+            'baz' => [
+              'configuration' => [
+                'id' => 'system_powered_by_block',
               ],
+              'region' => 'content',
             ],
           ],
         ],
         [
           'layout' => 'layout_twocol',
           'section' => [
-            'first' => [
-              'foo' => [
-                'block' => [
-                  'id' => 'test_block_instantiation',
-                  'display_message' => 'foo text',
-                ],
+            'foo' => [
+              'configuration' => [
+                'id' => 'test_block_instantiation',
+                'display_message' => 'foo text',
               ],
+              'region' => 'first',
             ],
-            'second' => [
-              'bar' => [
-                'block' => [
-                  'id' => 'test_block_instantiation',
-                  'display_message' => 'bar text',
-                ],
+            'bar' => [
+              'configuration' => [
+                'id' => 'test_block_instantiation',
+                'display_message' => 'bar text',
               ],
+              'region' => 'second',
             ],
           ],
         ],
@@ -179,12 +174,11 @@ public function testLayoutSectionFormatterAccess() {
       [
         'layout' => 'layout_onecol',
         'section' => [
-          'content' => [
-            'baz' => [
-              'block' => [
-                'id' => 'test_access',
-              ],
+          'baz' => [
+            'configuration' => [
+              'id' => 'test_access',
             ],
+            'region' => 'content',
           ],
         ],
       ],
@@ -218,12 +212,11 @@ public function testMultilingualLayoutSectionFormatter() {
       [
         'layout' => 'layout_onecol',
         'section' => [
-          'content' => [
-            'baz' => [
-              'block' => [
-                'id' => 'system_powered_by_block',
-              ],
+          'baz' => [
+            'configuration' => [
+              'id' => 'system_powered_by_block',
             ],
+            'region' => 'content',
           ],
         ],
       ],
@@ -234,21 +227,19 @@ public function testMultilingualLayoutSectionFormatter() {
         [
           'layout' => 'layout_twocol',
           'section' => [
-            'first' => [
-              'foo' => [
-                'block' => [
-                  'id' => 'test_block_instantiation',
-                  'display_message' => 'foo text',
-                ],
+            'foo' => [
+              'configuration' => [
+                'id' => 'test_block_instantiation',
+                'display_message' => 'foo text',
               ],
+              'region' => 'first',
             ],
-            'second' => [
-              'bar' => [
-                'block' => [
-                  'id' => 'test_block_instantiation',
-                  'display_message' => 'bar text',
-                ],
+            'bar' => [
+              'configuration' => [
+                'id' => 'test_block_instantiation',
+                'display_message' => 'bar text',
               ],
+              'region' => 'second',
             ],
           ],
         ],
diff --git a/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderFieldLayoutCompatibilityTest.php b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderFieldLayoutCompatibilityTest.php
index c3a23c7871..464ec194ae 100644
--- a/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderFieldLayoutCompatibilityTest.php
+++ b/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderFieldLayoutCompatibilityTest.php
@@ -8,6 +8,9 @@
 use Drupal\field\Entity\FieldConfig;
 use Drupal\field\Entity\FieldStorageConfig;
 use Drupal\KernelTests\KernelTestBase;
+use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
+use Drupal\layout_builder\Entity\LayoutEntity;
+use Drupal\layout_builder\Section;
 
 /**
  * Ensures that Layout Builder and Field Layout are compatible with each other.
@@ -99,22 +102,17 @@ public function testCompatibility() {
 
     // Install the Layout Builder, configure it for this entity display, and
     // reload the entity.
-    $this->enableModules(['layout_builder']);
-    $this->display->setThirdPartySetting('layout_builder', 'allow_custom', TRUE)->save();
-    $entity = EntityTestBaseFieldDisplay::load($entity->id());
+    $this->container->get('module_installer')->install(['layout_builder']);
+    $this->display = LayoutBuilderEntityViewDisplay::load($this->display->id());
+    $this->display->setOverridable()->save();
+    $entity = new LayoutEntity(EntityTestBaseFieldDisplay::load($entity->id()));
 
     // Without using Layout Builder for an override, the result has not changed.
     $new_markup = $this->renderEntity($entity);
     $this->assertSame($original_markup, $new_markup);
 
     // Add a layout override.
-    /** @var \Drupal\layout_builder\Field\LayoutSectionItemListInterface $field_list */
-    $field_list = $entity->layout_builder__layout;
-    $field_list->appendItem([
-      'layout' => 'layout_onecol',
-      'layout_settings' => [],
-      'section' => [],
-    ]);
+    $entity->appendSection(new Section('layout_onecol'));
     $entity->save();
 
     // The rendered entity has now changed. The non-configurable field is shown
@@ -128,7 +126,7 @@ public function testCompatibility() {
     $this->assertNotEmpty($this->cssSelect('.layout--onecol'));
 
     // Removing the layout restores the original rendering of the entity.
-    $field_list->removeItem(0);
+    $entity->removeSection(0);
     $entity->save();
     $new_markup = $this->renderEntity($entity);
     $this->assertSame($original_markup, $new_markup);
@@ -149,6 +147,9 @@ public function testCompatibility() {
    *   The rendered string output (typically HTML).
    */
   protected function renderEntity(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) {
+    if ($entity instanceof LayoutEntity) {
+      $entity = $entity->getEntity();
+    }
     $view_builder = $this->container->get('entity_type.manager')->getViewBuilder($entity->getEntityTypeId());
     $build = $view_builder->view($entity, $view_mode, $langcode);
     return $this->render($build);
diff --git a/core/modules/layout_builder/tests/src/Kernel/LayoutEntityTest.php b/core/modules/layout_builder/tests/src/Kernel/LayoutEntityTest.php
new file mode 100644
index 0000000000..b8fbf76c5f
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Kernel/LayoutEntityTest.php
@@ -0,0 +1,263 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\Kernel;
+
+use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\entity_test\Entity\EntityTestBaseFieldDisplay;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\layout_builder\Entity\LayoutEntity;
+use Drupal\layout_builder\Section;
+
+/**
+ * @coversDefaultClass \Drupal\layout_builder\Entity\LayoutEntity
+ *
+ * @group layout_builder
+ */
+class LayoutEntityTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'layout_builder',
+    'layout_discovery',
+    'entity_test',
+    'user',
+    'field',
+    'text',
+  ];
+
+  /**
+   * The layout entity decorator.
+   *
+   * @var \Drupal\layout_builder\Entity\LayoutEntity
+   */
+  protected $entityOverride;
+
+  /**
+   * The layout entity decorator.
+   *
+   * @var \Drupal\layout_builder\Entity\LayoutEntity
+   */
+  protected $entityDefaults;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    layout_builder_add_layout_section_field('entity_test_base_field_display', 'entity_test_base_field_display');
+
+    $display = EntityViewDisplay::create([
+      'targetEntityType' => 'entity_test_base_field_display',
+      'bundle' => 'entity_test_base_field_display',
+      'mode' => 'default',
+      'status' => TRUE,
+    ]);
+    $display->save();
+    $this->entityDefaults = new LayoutEntity($display);
+    $this->entityOverride = new LayoutEntity(EntityTestBaseFieldDisplay::create([
+      'layout_builder__layout' => [
+        [
+          'layout' => 'layout_onecol',
+          'section' => [
+            'test_display_configurable' => [
+              'region' => 'content',
+              'configuration' => [],
+            ],
+          ],
+        ],
+        [
+          'layout' => 'layout_onecol',
+          'layout_settings' => [
+            'foo' => 'bar',
+          ],
+          'section' => [
+            'test_display_configurable' => [
+              'region' => 'content',
+              'configuration' => [],
+            ],
+          ],
+        ],
+      ],
+    ]));
+  }
+
+  /**
+   * @covers ::isLayoutEnabled
+   */
+  public function testIsLayoutEnabled() {
+    $this->assertTrue($this->entityOverride->isLayoutEnabled());
+    $this->assertTrue($this->entityDefaults->isLayoutEnabled());
+  }
+
+  /**
+   * @covers ::isLayoutEmpty
+   */
+  public function testIsLayoutEmpty() {
+    $this->assertFalse($this->entityOverride->isLayoutEmpty());
+    $this->assertFalse($this->entityDefaults->isLayoutEmpty());
+  }
+
+  /**
+   * @covers ::getSections
+   */
+  public function testGetSections() {
+    $expected = [
+      new Section('layout_onecol', [], [
+        'test_display_configurable' => [
+          'region' => 'content',
+          'configuration' => [],
+        ],
+      ]),
+      new Section('layout_onecol', ['foo' => 'bar'], [
+        'test_display_configurable' => [
+          'region' => 'content',
+          'configuration' => [],
+        ],
+      ]),
+    ];
+    $this->assertEquals($expected, $this->entityOverride->getSections());
+    $this->assertEquals([$expected[0]], $this->entityDefaults->getSections());
+  }
+
+  /**
+   * @covers ::getSection
+   */
+  public function testGetSection() {
+    $this->assertInstanceOf(Section::class, $this->entityOverride->getSection(0));
+    $this->assertInstanceOf(Section::class, $this->entityDefaults->getSection(0));
+  }
+
+  /**
+   * @covers ::getSection
+   */
+  public function testGetSectionOverrideInvalidDelta() {
+    $this->setExpectedException(\OutOfBoundsException::class, 'Invalid delta');
+    $this->entityOverride->getSection(2);
+  }
+
+  /**
+   * @covers ::getSection
+   */
+  public function testGetSectionDefaultsInvalidDelta() {
+    $this->setExpectedException(\OutOfBoundsException::class, 'Invalid delta');
+    $this->entityDefaults->getSection(2);
+  }
+
+  /**
+   * @covers ::updateSection
+   */
+  public function testOverrideUpdateSection() {
+    $section = $this->entityOverride->getSection(0);
+
+    $section->setLayoutId('layout_twocol');
+    // The values are not yet updated on the entity.
+    $this->assertEquals('layout_onecol', $this->entityOverride->getSection(0)->getLayoutId());
+
+    $this->entityOverride->updateSection(0, $section);
+    $this->assertEquals('layout_twocol', $this->entityOverride->getSection(0)->getLayoutId());
+  }
+
+  /**
+   * @covers ::updateSection
+   */
+  public function testDefaultsUpdateSection() {
+    $section = $this->entityDefaults->getSection(0);
+
+    $section->setLayoutId('layout_twocol');
+    // The values are not yet updated on the entity.
+    $this->assertEquals('layout_onecol', $this->entityDefaults->getSection(0)->getLayoutId());
+
+    $this->entityDefaults->updateSection(0, $section);
+    $this->assertEquals('layout_twocol', $this->entityDefaults->getSection(0)->getLayoutId());
+  }
+
+  /**
+   * @covers ::addSection
+   */
+  public function testOverrideAddSection() {
+    $this->entityOverride->addSection(1, new Section('foo'));
+    $expected = [
+      new Section('layout_onecol', [], [
+        'test_display_configurable' => [
+          'region' => 'content',
+          'configuration' => [],
+        ],
+      ]),
+      new Section('foo'),
+      new Section('layout_onecol', ['foo' => 'bar'], [
+        'test_display_configurable' => [
+          'region' => 'content',
+          'configuration' => [],
+        ],
+      ]),
+    ];
+    $this->assertEquals($expected, $this->entityOverride->getSections());
+  }
+
+  /**
+   * @covers ::addSection
+   */
+  public function testDefaultsAddSection() {
+    $this->setExpectedException(\LogicException::class, 'Field Layout currently only supports a single section');
+    $this->entityDefaults->addSection(1, new Section('foo'));
+  }
+
+  /**
+   * @covers ::appendSection
+   */
+  public function testOverrideAppendSection() {
+    $this->entityOverride->appendSection(new Section('foo'));
+    $expected = [
+      new Section('layout_onecol', [], [
+        'test_display_configurable' => [
+          'region' => 'content',
+          'configuration' => [],
+        ],
+      ]),
+      new Section('layout_onecol', ['foo' => 'bar'], [
+        'test_display_configurable' => [
+          'region' => 'content',
+          'configuration' => [],
+        ],
+      ]),
+      new Section('foo'),
+    ];
+    $this->assertEquals($expected, $this->entityOverride->getSections());
+  }
+
+  /**
+   * @covers ::appendSection
+   */
+  public function testDefaultsAppendSection() {
+    $this->setExpectedException(\LogicException::class, 'Field Layout currently only supports a single section');
+    $this->entityDefaults->appendSection(new Section('foo'));
+  }
+
+  /**
+   * @covers ::removeSection
+   */
+  public function testOverrideRemoveSection() {
+    $this->entityOverride->removeSection(0);
+    $expected = [
+      new Section('layout_onecol', ['foo' => 'bar'], [
+        'test_display_configurable' => [
+          'region' => 'content',
+          'configuration' => [],
+        ],
+      ]),
+    ];
+    $this->assertEquals($expected, $this->entityOverride->getSections());
+  }
+
+  /**
+   * @covers ::removeSection
+   */
+  public function testDefaultsRemoveSection() {
+    $this->setExpectedException(\LogicException::class, 'Field Layout currently only supports a single section');
+    $this->entityDefaults->removeSection(0);
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Kernel/LayoutSectionItemListTest.php b/core/modules/layout_builder/tests/src/Kernel/LayoutSectionItemListTest.php
new file mode 100644
index 0000000000..b7c361c9d8
--- /dev/null
+++ b/core/modules/layout_builder/tests/src/Kernel/LayoutSectionItemListTest.php
@@ -0,0 +1,115 @@
+<?php
+
+namespace Drupal\Tests\layout_builder\Kernel;
+
+use Drupal\Core\Field\FieldItemListInterface;
+use Drupal\entity_test\Entity\EntityTest;
+use Drupal\layout_builder\Field\LayoutSectionItemListInterface;
+use Drupal\layout_builder\Section;
+use Drupal\Tests\field\Kernel\FieldKernelTestBase;
+
+/**
+ * Tests the field type for Layout Sections.
+ *
+ * @coversDefaultClass \Drupal\layout_builder\Field\LayoutSectionItemList
+ *
+ * @group layout_builder
+ */
+class LayoutSectionItemListTest extends FieldKernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['layout_builder', 'layout_discovery'];
+
+  /**
+   * {@inheritdoc}
+   */
+  public function testLayoutSectionItemList() {
+    layout_builder_add_layout_section_field('entity_test', 'entity_test');
+
+    $entity = EntityTest::create();
+    /** @var \Drupal\layout_builder\Field\LayoutSectionItemListInterface $field_list */
+    $field_list = $entity->layout_builder__layout;
+    $this->assertInstanceOf(LayoutSectionItemListInterface::class, $field_list);
+    $this->assertInstanceOf(FieldItemListInterface::class, $field_list);
+    $entity->save();
+
+    $field_list->appendSection(new Section('layout_twocol'));
+    $field_list->appendSection(new Section('layout_onecol'));
+    $field_list->appendSection(new Section('layout_threecol_25_50_25'));
+    $this->assertSame([
+      [
+        'layout' => 'layout_twocol',
+        'layout_settings' => [],
+        'section' => [],
+      ],
+      [
+        'layout' => 'layout_onecol',
+        'layout_settings' => [],
+        'section' => [],
+      ],
+      [
+        'layout' => 'layout_threecol_25_50_25',
+        'layout_settings' => [],
+        'section' => [],
+      ],
+    ], $field_list->getValue());
+
+    $field_list->addSection(1, new Section('layout_threecol_33_34_33'));
+    $this->assertSame([
+      [
+        'layout' => 'layout_twocol',
+        'layout_settings' => [],
+        'section' => [],
+      ],
+      [
+        'layout' => 'layout_threecol_33_34_33',
+        'layout_settings' => [],
+        'section' => [],
+      ],
+      [
+        'layout' => 'layout_onecol',
+        'layout_settings' => [],
+        'section' => [],
+      ],
+      [
+        'layout' => 'layout_threecol_25_50_25',
+        'layout_settings' => [],
+        'section' => [],
+      ],
+    ], $field_list->getValue());
+
+    $field_list->addSection($field_list->count(), new Section('layout_twocol_bricks'));
+    $this->assertSame([
+      [
+        'layout' => 'layout_twocol',
+        'layout_settings' => [],
+        'section' => [],
+      ],
+      [
+        'layout' => 'layout_threecol_33_34_33',
+        'layout_settings' => [],
+        'section' => [],
+      ],
+      [
+        'layout' => 'layout_onecol',
+        'layout_settings' => [],
+        'section' => [],
+      ],
+      [
+        'layout' => 'layout_threecol_25_50_25',
+        'layout_settings' => [],
+        'section' => [],
+      ],
+      [
+        'layout' => 'layout_twocol_bricks',
+        'layout_settings' => [],
+        'section' => [],
+      ],
+    ], $field_list->getValue());
+  }
+
+}
diff --git a/core/modules/layout_builder/tests/src/Kernel/LayoutSectionItemTest.php b/core/modules/layout_builder/tests/src/Kernel/LayoutSectionItemTest.php
deleted file mode 100644
index 0e13471c15..0000000000
--- a/core/modules/layout_builder/tests/src/Kernel/LayoutSectionItemTest.php
+++ /dev/null
@@ -1,89 +0,0 @@
-<?php
-
-namespace Drupal\Tests\layout_builder\Kernel;
-
-use Drupal\Core\Field\FieldItemInterface;
-use Drupal\Core\Field\FieldItemListInterface;
-use Drupal\entity_test\Entity\EntityTest;
-use Drupal\layout_builder\Field\LayoutSectionItemInterface;
-use Drupal\layout_builder\Field\LayoutSectionItemListInterface;
-use Drupal\Tests\field\Kernel\FieldKernelTestBase;
-
-/**
- * Tests the field type for Layout Sections.
- *
- * @group layout_builder
- */
-class LayoutSectionItemTest extends FieldKernelTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = ['layout_builder', 'layout_discovery'];
-
-  /**
-   * Tests using entity fields of the layout section field type.
-   */
-  public function testLayoutSectionItem() {
-    layout_builder_add_layout_section_field('entity_test', 'entity_test');
-
-    $entity = EntityTest::create();
-    /** @var \Drupal\layout_builder\Field\LayoutSectionItemListInterface $field_list */
-    $field_list = $entity->layout_builder__layout;
-
-    // Test sample item generation.
-    $field_list->generateSampleItems();
-    $this->entityValidateAndSave($entity);
-
-    $field = $field_list->get(0);
-    $this->assertInstanceOf(LayoutSectionItemInterface::class, $field);
-    $this->assertInstanceOf(FieldItemInterface::class, $field);
-    $this->assertSame('section', $field->mainPropertyName());
-    $this->assertSame('layout_onecol', $field->layout);
-    $this->assertSame([], $field->layout_settings);
-    $this->assertSame([], $field->section);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function testLayoutSectionItemList() {
-    layout_builder_add_layout_section_field('entity_test', 'entity_test');
-
-    $entity = EntityTest::create();
-    /** @var \Drupal\layout_builder\Field\LayoutSectionItemListInterface $field_list */
-    $field_list = $entity->layout_builder__layout;
-    $this->assertInstanceOf(LayoutSectionItemListInterface::class, $field_list);
-    $this->assertInstanceOf(FieldItemListInterface::class, $field_list);
-    $entity->save();
-
-    $field_list->appendItem(['layout' => 'layout_twocol']);
-    $field_list->appendItem(['layout' => 'layout_onecol']);
-    $field_list->appendItem(['layout' => 'layout_threecol_25_50_25']);
-    $this->assertSame([
-      ['layout' => 'layout_twocol'],
-      ['layout' => 'layout_onecol'],
-      ['layout' => 'layout_threecol_25_50_25'],
-    ], $field_list->getValue());
-
-    $field_list->addItem(1, ['layout' => 'layout_threecol_33_34_33']);
-    $this->assertSame([
-      ['layout' => 'layout_twocol'],
-      ['layout' => 'layout_threecol_33_34_33'],
-      ['layout' => 'layout_onecol'],
-      ['layout' => 'layout_threecol_25_50_25'],
-    ], $field_list->getValue());
-
-    $field_list->addItem($field_list->count(), ['layout' => 'layout_twocol_bricks']);
-    $this->assertSame([
-      ['layout' => 'layout_twocol'],
-      ['layout' => 'layout_threecol_33_34_33'],
-      ['layout' => 'layout_onecol'],
-      ['layout' => 'layout_threecol_25_50_25'],
-      ['layout' => 'layout_twocol_bricks'],
-    ], $field_list->getValue());
-  }
-
-}
diff --git a/core/modules/layout_builder/tests/src/Unit/LayoutSectionBuilderTest.php b/core/modules/layout_builder/tests/src/Unit/LayoutSectionBuilderTest.php
index 3e5b2ffad1..3adb457bb0 100644
--- a/core/modules/layout_builder/tests/src/Unit/LayoutSectionBuilderTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/LayoutSectionBuilderTest.php
@@ -7,15 +7,17 @@
 use Drupal\Core\Block\BlockManagerInterface;
 use Drupal\Core\Block\BlockPluginInterface;
 use Drupal\Core\Cache\Cache;
-use Drupal\Core\Layout\LayoutInterface;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\Layout\LayoutDefault;
+use Drupal\Core\Layout\LayoutDefinition;
 use Drupal\Core\Layout\LayoutPluginManagerInterface;
 use Drupal\Core\Plugin\Context\ContextHandlerInterface;
 use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
 use Drupal\Core\Plugin\ContextAwarePluginInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\layout_builder\LayoutSectionBuilder;
+use Drupal\layout_builder\Section;
 use Drupal\Tests\UnitTestCase;
-use Prophecy\Argument;
 
 /**
  * @coversDefaultClass \Drupal\layout_builder\LayoutSectionBuilder
@@ -72,6 +74,13 @@ class LayoutSectionBuilderTest extends UnitTestCase {
    */
   protected $layout;
 
+  /**
+   * The layout definition.
+   *
+   * @var \Drupal\Core\Layout\LayoutDefinition
+   */
+  protected $pluginDefinition;
+
   /**
    * {@inheritdoc}
    */
@@ -83,10 +92,22 @@ protected function setUp() {
     $this->blockManager = $this->prophesize(BlockManagerInterface::class);
     $this->contextHandler = $this->prophesize(ContextHandlerInterface::class);
     $this->contextRepository = $this->prophesize(ContextRepositoryInterface::class);
-    $this->layoutSectionBuilder = new LayoutSectionBuilder($this->account->reveal(), $this->layoutPluginManager->reveal(), $this->blockManager->reveal(), $this->contextHandler->reveal(), $this->contextRepository->reveal());
+    $this->layoutSectionBuilder = new LayoutSectionBuilder($this->account->reveal(), $this->blockManager->reveal(), $this->contextHandler->reveal(), $this->contextRepository->reveal());
 
-    $this->layout = $this->prophesize(LayoutInterface::class);
-    $this->layoutPluginManager->createInstance('layout_onecol', [])->willReturn($this->layout->reveal());
+    $container = new ContainerBuilder();
+    $container->set('plugin.manager.core.layout', $this->layoutPluginManager->reveal());
+    \Drupal::setContainer($container);
+
+    $this->pluginDefinition = new LayoutDefinition([
+      'theme_hook' => 'onecol',
+      'regions' => [
+        'content' => [
+          'label' => 'Content',
+        ],
+      ],
+    ]);
+    $this->layout = new LayoutDefault([], 'layout_onecol', $this->pluginDefinition);
+    $this->layoutPluginManager->createInstance('layout_onecol', [])->willReturn($this->layout);
   }
 
   /**
@@ -103,7 +124,6 @@ public function testBuildSection() {
       '#derivative_plugin_id' => NULL,
       'content' => $block_content,
     ];
-    $this->layout->build(['content' => ['some_uuid' => $render_array]])->willReturnArgument(0);
 
     $block = $this->prophesize(BlockPluginInterface::class);
     $this->blockManager->createInstance('block_plugin_id', ['id' => 'block_plugin_id'])->willReturn($block->reveal());
@@ -119,15 +139,14 @@ public function testBuildSection() {
     $block->getDerivativeId()->willReturn(NULL);
     $block->getConfiguration()->willReturn([]);
 
-    $section = [
-      'content' => [
-        'some_uuid' => [
-          'block' => [
-            'id' => 'block_plugin_id',
-          ],
+    $section = new Section('layout_onecol', [], [
+      'some_uuid' => [
+        'configuration' => [
+          'id' => 'block_plugin_id',
         ],
+        'region' => 'content',
       ],
-    ];
+    ]);
     $expected = [
       '#cache' => [
         'contexts' => [],
@@ -137,8 +156,11 @@ public function testBuildSection() {
       'content' => [
         'some_uuid' => $render_array,
       ],
+      '#settings' => [],
+      '#layout' => $this->pluginDefinition,
+      '#theme' => 'onecol',
     ];
-    $result = $this->layoutSectionBuilder->buildSection('layout_onecol', [], $section);
+    $result = $this->layoutSectionBuilder->buildSection($section);
     $this->assertEquals($expected, $result);
   }
 
@@ -146,8 +168,6 @@ public function testBuildSection() {
    * @covers ::buildSection
    */
   public function testBuildSectionAccessDenied() {
-    $this->layout->build([])->willReturn([]);
-
     $block = $this->prophesize(BlockPluginInterface::class);
     $this->blockManager->createInstance('block_plugin_id', ['id' => 'block_plugin_id'])->willReturn($block->reveal());
 
@@ -155,23 +175,26 @@ public function testBuildSectionAccessDenied() {
     $block->access($this->account->reveal(), TRUE)->willReturn($access_result);
     $block->build()->shouldNotBeCalled();
 
-    $section = [
-      'content' => [
-        'some_uuid' => [
-          'block' => [
-            'id' => 'block_plugin_id',
-          ],
+    $section = new Section('layout_onecol', [], [
+      'some_uuid' => [
+        'configuration' => [
+          'id' => 'block_plugin_id',
         ],
+        'region' => 'content',
       ],
-    ];
+    ]);
     $expected = [
       '#cache' => [
         'contexts' => [],
         'tags' => [],
         'max-age' => -1,
       ],
+      'content' => [],
+      '#settings' => [],
+      '#layout' => $this->pluginDefinition,
+      '#theme' => 'onecol',
     ];
-    $result = $this->layoutSectionBuilder->buildSection('layout_onecol', [], $section);
+    $result = $this->layoutSectionBuilder->buildSection($section);
     $this->assertEquals($expected, $result);
   }
 
@@ -179,17 +202,19 @@ public function testBuildSectionAccessDenied() {
    * @covers ::buildSection
    */
   public function testBuildSectionEmpty() {
-    $this->layout->build([])->willReturn([]);
-
-    $section = [];
+    $section = new Section('layout_onecol');
     $expected = [
       '#cache' => [
         'contexts' => [],
         'tags' => [],
         'max-age' => -1,
       ],
+      'content' => [],
+      '#settings' => [],
+      '#layout' => $this->pluginDefinition,
+      '#theme' => 'onecol',
     ];
-    $result = $this->layoutSectionBuilder->buildSection('layout_onecol', [], $section);
+    $result = $this->layoutSectionBuilder->buildSection($section);
     $this->assertEquals($expected, $result);
   }
 
@@ -207,7 +232,6 @@ public function testContextAwareBlock() {
       '#derivative_plugin_id' => NULL,
       'content' => [],
     ];
-    $this->layout->build(['content' => ['some_uuid' => $render_array]])->willReturnArgument(0);
 
     $block = $this->prophesize(BlockPluginInterface::class)->willImplement(ContextAwarePluginInterface::class);
     $this->blockManager->createInstance('block_plugin_id', ['id' => 'block_plugin_id'])->willReturn($block->reveal());
@@ -227,15 +251,14 @@ public function testContextAwareBlock() {
     $this->contextRepository->getRuntimeContexts([])->willReturn([]);
     $this->contextHandler->applyContextMapping($block->reveal(), [])->shouldBeCalled();
 
-    $section = [
-      'content' => [
-        'some_uuid' => [
-          'block' => [
-            'id' => 'block_plugin_id',
-          ],
+    $section = new Section('layout_onecol', [], [
+      'some_uuid' => [
+        'configuration' => [
+          'id' => 'block_plugin_id',
         ],
+        'region' => 'content',
       ],
-    ];
+    ]);
     $expected = [
       '#cache' => [
         'contexts' => [],
@@ -245,8 +268,11 @@ public function testContextAwareBlock() {
       'content' => [
         'some_uuid' => $render_array,
       ],
+      '#settings' => [],
+      '#layout' => $this->pluginDefinition,
+      '#theme' => 'onecol',
     ];
-    $result = $this->layoutSectionBuilder->buildSection('layout_onecol', [], $section);
+    $result = $this->layoutSectionBuilder->buildSection($section);
     $this->assertEquals($expected, $result);
   }
 
@@ -255,47 +281,14 @@ public function testContextAwareBlock() {
    * @covers ::getBlock
    */
   public function testBuildSectionMissingPluginId() {
-    $section = [
-      'content' => [
-        'some_uuid' => [
-          'block' => [],
-        ],
+    $section = new Section('layout_onecol', [], [
+      'some_uuid' => [
+        'configuration' => [],
+        'region' => 'content',
       ],
-    ];
+    ]);
     $this->setExpectedException(PluginException::class, 'No plugin ID specified for block with "some_uuid" UUID');
-    $this->layoutSectionBuilder->buildSection('layout_onecol', [], $section);
-  }
-
-  /**
-   * @covers ::buildSection
-   *
-   * @dataProvider providerTestBuildSectionMalformedData
-   */
-  public function testBuildSectionMalformedData($section, $message) {
-    $this->layout->build(Argument::type('array'))->willReturnArgument(0);
-    $this->layout->getPluginId()->willReturn('the_plugin_id');
-    $this->setExpectedException(\InvalidArgumentException::class, $message);
-    $this->layoutSectionBuilder->buildSection('layout_onecol', [], $section);
-  }
-
-  /**
-   * Provides test data for ::testBuildSectionMalformedData().
-   */
-  public function providerTestBuildSectionMalformedData() {
-    $data = [];
-    $data['invalid_region'] = [
-      ['content' => 'bar'],
-      'The "content" region in the "the_plugin_id" layout has invalid configuration',
-    ];
-    $data['invalid_configuration'] = [
-      ['content' => ['some_uuid' => 'bar']],
-      'The block with UUID of "some_uuid" has invalid configuration',
-    ];
-    $data['invalid_blocks'] = [
-      ['content' => ['some_uuid' => []]],
-      'The block with UUID of "some_uuid" has invalid configuration',
-    ];
-    return $data;
+    $this->layoutSectionBuilder->buildSection($section);
   }
 
 }
diff --git a/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreRepositoryTest.php b/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreRepositoryTest.php
index a652d4a56d..b24cbf1967 100644
--- a/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreRepositoryTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/LayoutTempstoreRepositoryTest.php
@@ -2,11 +2,12 @@
 
 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\FieldableEntityInterface;
 use Drupal\Core\Entity\RevisionableInterface;
 use Drupal\Core\Language\Language;
+use Drupal\layout_builder\Entity\LayoutEntity;
 use Drupal\layout_builder\LayoutTempstoreRepository;
 use Drupal\Tests\UnitTestCase;
 use Drupal\user\SharedTempStore;
@@ -30,7 +31,7 @@ public function testGetFromIdEmptyTempstore() {
     $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 = $this->prophesize(FieldableEntityInterface::class);
     $entity->getEntityTypeId()->willReturn('the_entity_type_id');
     $entity->id()->willReturn('the_entity_id');
     $entity->language()->willReturn(new Language(['id' => 'en']));
@@ -43,7 +44,7 @@ public function testGetFromIdEmptyTempstore() {
 
     $repository = new LayoutTempstoreRepository($tempstore_factory->reveal(), $entity_type_manager->reveal());
 
-    $result = $repository->getFromId('the_entity_type_id', 'the_entity_id');
+    $result = $repository->getFromId('the_entity_type_id', 'the_entity_id')->getEntity();
     $this->assertSame($entity->reveal(), $result);
   }
 
@@ -53,13 +54,13 @@ public function testGetFromIdEmptyTempstore() {
    * @covers ::generateTempstoreId
    */
   public function testGetFromIdLoadedTempstore() {
-    $tempstore_entity = $this->prophesize(EntityInterface::class);
+    $tempstore_entity = $this->prophesize(FieldableEntityInterface::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 = $this->prophesize(FieldableEntityInterface::class);
     $entity->getEntityTypeId()->willReturn('the_entity_type_id');
     $entity->id()->willReturn('the_entity_id');
     $entity->language()->willReturn(new Language(['id' => 'en']));
@@ -72,7 +73,7 @@ public function testGetFromIdLoadedTempstore() {
 
     $repository = new LayoutTempstoreRepository($tempstore_factory->reveal(), $entity_type_manager->reveal());
 
-    $result = $repository->getFromId('the_entity_type_id', 'the_entity_id');
+    $result = $repository->getFromId('the_entity_type_id', 'the_entity_id')->getEntity();
     $this->assertSame($tempstore_entity->reveal(), $result);
     $this->assertNotSame($entity->reveal(), $result);
   }
@@ -89,7 +90,7 @@ public function testGetFromIdRevisionable() {
     $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 = $this->prophesize(FieldableEntityInterface::class)->willImplement(RevisionableInterface::class);
     $entity->getEntityTypeId()->willReturn('the_entity_type_id');
     $entity->id()->willReturn('the_entity_id');
     $entity->language()->willReturn(new Language(['id' => 'en']));
@@ -103,7 +104,7 @@ public function testGetFromIdRevisionable() {
 
     $repository = new LayoutTempstoreRepository($tempstore_factory->reveal(), $entity_type_manager->reveal());
 
-    $result = $repository->getFromId('the_entity_type_id', 'the_entity_id');
+    $result = $repository->getFromId('the_entity_type_id', 'the_entity_id')->getEntity();
     $this->assertSame($entity->reveal(), $result);
   }
 
@@ -121,13 +122,13 @@ public function testGetInvalidEntity() {
 
     $repository = new LayoutTempstoreRepository($tempstore_factory->reveal(), $entity_type_manager->reveal());
 
-    $entity = $this->prophesize(EntityInterface::class);
+    $entity = $this->prophesize(FieldableEntityInterface::class);
     $entity->language()->willReturn(new Language(['id' => 'en']));
     $entity->getEntityTypeId()->willReturn('the_entity_type_id');
     $entity->id()->willReturn('the_entity_id');
 
     $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());
+    $repository->get(new LayoutEntity($entity->reveal()));
   }
 
 }
diff --git a/core/modules/layout_builder/tests/src/Unit/SectionTest.php b/core/modules/layout_builder/tests/src/Unit/SectionTest.php
index 33a338706e..b340c40c7e 100644
--- a/core/modules/layout_builder/tests/src/Unit/SectionTest.php
+++ b/core/modules/layout_builder/tests/src/Unit/SectionTest.php
@@ -24,177 +24,223 @@ class SectionTest extends UnitTestCase {
   protected function setUp() {
     parent::setUp();
 
-    $this->section = new Section([
-      'empty-region' => [],
-      'some-region' => [
-        'existing-uuid' => [
-          'block' => [
-            'id' => 'existing-block-id',
-          ],
+    $this->section = new Section('layout_onecol', [], [
+      'existing-uuid' => [
+        'configuration' => [
+          'id' => 'existing-block-id',
         ],
+        'region' => 'some-region',
       ],
-      'ordered-region' => [
-        'first-uuid' => [
-          'block' => [
-            'id' => 'first-block-id',
-          ],
+      'second-uuid' => [
+        'configuration' => [
+          'id' => 'second-block-id',
         ],
-        'second-uuid' => [
-          'block' => [
-            'id' => 'second-block-id',
-          ],
+        'region' => 'ordered-region',
+        'weight' => 1,
+      ],
+      'first-uuid' => [
+        'configuration' => [
+          'id' => 'first-block-id',
         ],
+        'region' => 'ordered-region',
+        'weight' => 0,
       ],
     ]);
   }
 
   /**
    * @covers ::__construct
+   * @covers ::setBlock
    * @covers ::getValue
    */
   public function testGetValue() {
     $expected = [
-      'empty-region' => [],
-      'some-region' => [
-        'existing-uuid' => [
-          'block' => [
-            'id' => 'existing-block-id',
-          ],
+      'existing-uuid' => [
+        'configuration' => [
+          'id' => 'existing-block-id',
         ],
+        'region' => 'some-region',
+        'weight' => 0,
       ],
-      'ordered-region' => [
-        'first-uuid' => [
-          'block' => [
-            'id' => 'first-block-id',
-          ],
+      'first-uuid' => [
+        'configuration' => [
+          'id' => 'first-block-id',
         ],
-        'second-uuid' => [
-          'block' => [
-            'id' => 'second-block-id',
-          ],
+        'region' => 'ordered-region',
+        'weight' => 0,
+      ],
+      'second-uuid' => [
+        'configuration' => [
+          'id' => 'second-block-id',
         ],
+        'region' => 'ordered-region',
+        'weight' => 1,
       ],
     ];
     $result = $this->section->getValue();
+    $this->assertEquals($expected, $result);
     $this->assertSame($expected, $result);
   }
 
-  /**
-   * @covers ::getBlock
-   */
-  public function testGetBlockInvalidRegion() {
-    $this->setExpectedException(\InvalidArgumentException::class, 'Invalid region');
-    $this->section->getBlock('invalid-region', 'existing-uuid');
-  }
-
   /**
    * @covers ::getBlock
    */
   public function testGetBlockInvalidUuid() {
     $this->setExpectedException(\InvalidArgumentException::class, 'Invalid UUID');
-    $this->section->getBlock('some-region', 'invalid-uuid');
+    $this->section->getBlock('invalid-uuid');
   }
 
   /**
    * @covers ::getBlock
    */
   public function testGetBlock() {
-    $expected = ['block' => ['id' => 'existing-block-id']];
+    $expected = [
+      'configuration' => ['id' => 'existing-block-id'],
+      'region' => 'some-region',
+      'weight' => 0,
+    ];
 
-    $block = $this->section->getBlock('some-region', 'existing-uuid');
+    $block = $this->section->getBlock('existing-uuid');
+    $this->assertEquals($expected, $block);
     $this->assertSame($expected, $block);
   }
 
+  /**
+   * @covers ::validateBlock
+   * @dataProvider providerTestValidateBlock
+   */
+  public function testValidateBlock($section, $message) {
+    $this->setExpectedException(\InvalidArgumentException::class, $message);
+    new Section('the_plugin_id', [], $section);
+  }
+
+  /**
+   * Provides test data for ::testValidateBlock().
+   */
+  public function providerTestValidateBlock() {
+    $data = [];
+    $data['missing_region'] = [
+      ['some_uuid' => []],
+      'The block with UUID of "some_uuid" is missing a region',
+    ];
+    $data['invalid_blocks'] = [
+      ['some_uuid' => ['region' => 'the_region']],
+      'The block with UUID of "some_uuid" is missing configuration',
+    ];
+    return $data;
+  }
+
   /**
    * @covers ::removeBlock
    */
   public function testRemoveBlock() {
-    $this->section->removeBlock('some-region', 'existing-uuid');
+    $this->section->removeBlock('existing-uuid');
     $expected = [
-      'ordered-region' => [
-        'first-uuid' => [
-          'block' => [
-            'id' => 'first-block-id',
-          ],
+      'first-uuid' => [
+        'configuration' => [
+          'id' => 'first-block-id',
         ],
-        'second-uuid' => [
-          'block' => [
-            'id' => 'second-block-id',
-          ],
+        'region' => 'ordered-region',
+        'weight' => 0,
+      ],
+      'second-uuid' => [
+        'configuration' => [
+          'id' => 'second-block-id',
         ],
+        'region' => 'ordered-region',
+        'weight' => 1,
       ],
     ];
-    $this->assertSame($expected, $this->section->getValue());
+    $result = $this->section->getValue();
+    $this->assertEquals($expected, $result);
+    $this->assertSame($expected, $result);
   }
 
   /**
    * @covers ::addBlock
+   * @covers ::getNextHighestWeight
+   * @covers ::getBlocksByRegion
    */
   public function testAddBlock() {
-    $this->section->addBlock('some-region', 'new-uuid', []);
+    $this->section->addBlock('some-region', 'new-uuid', ['configuration' => []]);
     $expected = [
-      'empty-region' => [],
-      'some-region' => [
-        'new-uuid' => [],
-        'existing-uuid' => [
-          'block' => [
-            'id' => 'existing-block-id',
-          ],
+      'existing-uuid' => [
+        'configuration' => [
+          'id' => 'existing-block-id',
         ],
+        'region' => 'some-region',
+        'weight' => 0,
       ],
-      'ordered-region' => [
-        'first-uuid' => [
-          'block' => [
-            'id' => 'first-block-id',
-          ],
+      'first-uuid' => [
+        'configuration' => [
+          'id' => 'first-block-id',
         ],
-        'second-uuid' => [
-          'block' => [
-            'id' => 'second-block-id',
-          ],
+        'region' => 'ordered-region',
+        'weight' => 0,
+      ],
+      'second-uuid' => [
+        'configuration' => [
+          'id' => 'second-block-id',
         ],
+        'region' => 'ordered-region',
+        'weight' => 1,
+      ],
+      'new-uuid' => [
+        'configuration' => [],
+        'region' => 'some-region',
+        'weight' => 1,
       ],
     ];
-    $this->assertSame($expected, $this->section->getValue());
+    $result = $this->section->getValue();
+    $this->assertEquals($expected, $result);
+    $this->assertSame($expected, $result);
   }
 
   /**
    * @covers ::insertBlock
+   * @covers ::getBlocksByRegion
    */
   public function testInsertBlock() {
-    $this->section->insertBlock('ordered-region', 'new-uuid', [], 'first-uuid');
+    $this->section->insertBlock('ordered-region', 'new-uuid', ['configuration' => []], 'first-uuid');
     $expected = [
-      'empty-region' => [],
-      'some-region' => [
-        'existing-uuid' => [
-          'block' => [
-            'id' => 'existing-block-id',
-          ],
+      'existing-uuid' => [
+        'configuration' => [
+          'id' => 'existing-block-id',
         ],
+        'region' => 'some-region',
+        'weight' => 0,
       ],
-      'ordered-region' => [
-        'first-uuid' => [
-          'block' => [
-            'id' => 'first-block-id',
-          ],
+      'first-uuid' => [
+        'configuration' => [
+          'id' => 'first-block-id',
         ],
-        'new-uuid' => [],
-        'second-uuid' => [
-          'block' => [
-            'id' => 'second-block-id',
-          ],
+        'region' => 'ordered-region',
+        'weight' => 0,
+      ],
+      'new-uuid' => [
+        'configuration' => [],
+        'region' => 'ordered-region',
+        'weight' => 1,
+      ],
+      'second-uuid' => [
+        'configuration' => [
+          'id' => 'second-block-id',
         ],
+        'region' => 'ordered-region',
+        'weight' => 2,
       ],
     ];
-    $this->assertSame($expected, $this->section->getValue());
+    $result = $this->section->getValue();
+    $this->assertEquals($expected, $result);
+    $this->assertSame($expected, $result);
   }
 
   /**
    * @covers ::insertBlock
    */
-  public function testInsertBlockInvalidRegion() {
-    $this->setExpectedException(\InvalidArgumentException::class, 'Invalid region');
-    $this->section->insertBlock('invalid-region', 'new-uuid', [], 'first-uuid');
+  public function testInsertBlockValidUuidRegionMismatch() {
+    $this->setExpectedException(\InvalidArgumentException::class, 'Invalid preceding UUID');
+    $this->section->insertBlock('ordered-region', 'new-uuid', ['configuration' => []], 'existing-uuid');
   }
 
   /**
@@ -202,7 +248,7 @@ public function testInsertBlockInvalidRegion() {
    */
   public function testInsertBlockInvalidUuid() {
     $this->setExpectedException(\InvalidArgumentException::class, 'Invalid preceding UUID');
-    $this->section->insertBlock('ordered-region', 'new-uuid', [], 'invalid-uuid');
+    $this->section->insertBlock('ordered-region', 'new-uuid', ['configuration' => []], 'invalid-uuid');
   }
 
   /**
@@ -210,7 +256,7 @@ public function testInsertBlockInvalidUuid() {
    */
   public function testUpdateBlock() {
     $this->section->updateBlock('some-region', 'existing-uuid', [
-      'block' => [
+      'configuration' => [
         'id' => 'existing-block-id',
         'settings' => [
           'foo' => 'bar',
@@ -219,39 +265,34 @@ public function testUpdateBlock() {
     ]);
 
     $expected = [
-      'empty-region' => [],
-      'some-region' => [
-        'existing-uuid' => [
-          'block' => [
-            'id' => 'existing-block-id',
-            'settings' => [
-              'foo' => 'bar',
-            ],
+      'existing-uuid' => [
+        'configuration' => [
+          'id' => 'existing-block-id',
+          'settings' => [
+            'foo' => 'bar',
           ],
         ],
+        'region' => 'some-region',
+        'weight' => 0,
       ],
-      'ordered-region' => [
-        'first-uuid' => [
-          'block' => [
-            'id' => 'first-block-id',
-          ],
+      'first-uuid' => [
+        'configuration' => [
+          'id' => 'first-block-id',
         ],
-        'second-uuid' => [
-          'block' => [
-            'id' => 'second-block-id',
-          ],
+        'region' => 'ordered-region',
+        'weight' => 0,
+      ],
+      'second-uuid' => [
+        'configuration' => [
+          'id' => 'second-block-id',
         ],
+        'region' => 'ordered-region',
+        'weight' => 1,
       ],
     ];
-    $this->assertSame($expected, $this->section->getValue());
-  }
-
-  /**
-   * @covers ::updateBlock
-   */
-  public function testUpdateBlockInvalidRegion() {
-    $this->setExpectedException(\InvalidArgumentException::class, 'Invalid region');
-    $this->section->updateBlock('invalid-region', 'new-uuid', []);
+    $result = $this->section->getValue();
+    $this->assertEquals($expected, $result);
+    $this->assertSame($expected, $result);
   }
 
   /**
@@ -259,7 +300,7 @@ public function testUpdateBlockInvalidRegion() {
    */
   public function testUpdateBlockInvalidUuid() {
     $this->setExpectedException(\InvalidArgumentException::class, 'Invalid UUID');
-    $this->section->updateBlock('ordered-region', 'new-uuid', []);
+    $this->section->updateBlock('ordered-region', 'new-uuid', ['configuration' => []]);
   }
 
 }
