diff --git a/migrations/panelizer_entity_view_display.yml b/migrations/panelizer_entity_view_display.yml
new file mode 100644
index 0000000..34c4661
--- /dev/null
+++ b/migrations/panelizer_entity_view_display.yml
@@ -0,0 +1,46 @@
+id: panelizer_entity_view_display
+label: 'Panelizer display to entity view display'
+source:
+  plugin: panelizer_layout
+  scope: default
+  constants:
+    block_settings_data_type_prefix: 'block.settings'
+process:
+  entity_type: entity_type
+  bundle: bundle
+  view_mode: view_mode
+  layout_id: layout
+  layout_settings: layout_settings
+  allow_custom:
+    plugin: callback
+    source: custom
+    callable: boolval
+  components:
+    plugin: sub_process
+    source: blocks
+    process:
+      uuid: uuid
+      region: region
+      weight: weight
+      # Derive the config schema data type for the block settings, which is
+      # needed by the extract_configuration plugin.
+      data_type:
+        plugin: concat
+        delimiter: '.'
+        source:
+          - 'constants/block_settings_data_type_prefix'
+          - id
+      configuration:
+        plugin: extract_configuration
+        source: '@data_type'
+        bypass: false
+      # This may need a specialized process plugin to handle CTools entity
+      # field blocks. (EntityFieldDeriver --> FieldBlockDeriver)
+      'configuration/id': id
+      additional:
+        plugin: default_value
+        default_value: {}
+destination:
+  plugin: layout_section
+  # This line should be removed once Layout Builder is opt-in.
+  overwrite: true
diff --git a/panelizer.module b/panelizer.module
index badc90d..9b2c6d3 100644
--- a/panelizer.module
+++ b/panelizer.module
@@ -7,7 +7,9 @@
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Entity\RevisionableInterface;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
 use Drupal\Core\Url;
+use Drupal\migrate\Row;
 use Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant;
 
 /**
@@ -405,3 +407,40 @@ function template_preprocess_panelizer_view_mode(&$variables) {
   $panelizer_plugin->preprocessViewMode($variables, $entity, $panels_display, $view_mode);
 }
 
+/**
+ * Implements hook_migrate_MIGRATION_ID_prepare_row().
+ */
+function panelizer_migrate_panelizer_entity_view_display_prepare_row(Row $row) {
+  $display = entity_get_display(
+    $row->getSourceProperty('entity_type'),
+    $row->getSourceProperty('bundle'),
+    $row->getSourceProperty('view_mode')
+  );
+  
+  $layouts = $display->getThirdPartySetting('panelizer', 'displays', []);
+  if (count($layouts) > 1) {
+    $message = t('Cowardly refusing to migrate the @id entity view display to Layout Builder because it does not yet support multiple defaults.', [
+      '@id' => $display->id(),
+    ]);
+    Drupal::logger('panelizer')->warning((string) $message);
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function panelizer_form_panels_block_page_content_alter(array &$form) {
+  $children = Element::children($form['blocks']);
+
+  foreach ($children as $block_id) {
+    if (strpos($block_id, 'region-') === 0) {
+      continue;
+    }
+    // Expose the block label to help with testing.
+    $form['blocks'][$block_id]['region']['#title'] = t('Region for "@label"', [
+      '@label' => $form['blocks'][$block_id]['label']['#markup'],
+    ]);
+  }
+}
diff --git a/src/Plugin/migrate/destination/LayoutSection.php b/src/Plugin/migrate/destination/LayoutSection.php
new file mode 100644
index 0000000..e771bd5
--- /dev/null
+++ b/src/Plugin/migrate/destination/LayoutSection.php
@@ -0,0 +1,101 @@
+<?php
+
+namespace Drupal\panelizer\Plugin\migrate\destination;
+
+use Drupal\layout_builder\Section;
+use Drupal\migrate\Plugin\migrate\destination\DestinationBase;
+use Drupal\migrate\Plugin\MigrationInterface;
+use Drupal\migrate\Row;
+
+/**
+ * @MigrateDestination(
+ *   id = "layout_section",
+ * )
+ */
+class LayoutSection extends DestinationBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration) {
+    $configuration += [
+      'overwrite' => FALSE,
+    ];
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function import(Row $row, array $old_destination_id_values = []) {
+    $values = $row->getDestination();
+
+    /** @var \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface $display */
+    $display = entity_get_display(
+      $values['entity_type'],
+      $values['bundle'],
+      $values['view_mode']
+    );
+    if ($row->hasDestinationProperty('allow_custom')) {
+      $display->setOverridable($row->getDestinationProperty('allow_custom'));
+    }
+    if ($this->configuration['overwrite']) {
+      while (count($display)) {
+        $display->removeSection(0);
+      }
+    }
+    $display->appendSection( Section::fromArray($values) )->save();
+
+    return [
+      'entity_type' => $display->getTargetEntityTypeId(),
+      'bundle' => $display->getTargetBundle(),
+      'view_mode' => $display->getMode(),
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function rollback(array $destination_identifier) {
+    /** @var \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface $display */
+    $display = entity_get_display(
+      $destination_identifier['entity_type'],
+      $destination_identifier['bundle'],
+      $destination_identifier['view_mode']
+    );
+    $display->removeSection(0)->save();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    return [
+      'entity_type' => [
+        'type' => 'string',
+      ],
+      'bundle' => [
+        'type' => 'string',
+      ],
+      'view_mode' => [
+        'type' => 'string',
+      ],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields(MigrationInterface $migration = NULL) {
+    return [
+      'entity_type' => $this->t('The target entity type ID of the entity view display'),
+      'bundle' => $this->t('The target bundle of the entity view display'),
+      'view_mode' => $this->t('The target view mode of the entity view display'),
+      'layout_id' => $this->t('The plugin ID of the layout'),
+      'layout_settings' => $this->t('Additional settings for the layout plugin'),
+      'components' => $this->t('Array of blocks in the layout'),
+      'allow_custom' => $this->t('Whether users are allowed to customize the layout per-entity'),
+    ];
+  }
+
+}
diff --git a/src/Plugin/migrate/process/ExtractConfiguration.php b/src/Plugin/migrate/process/ExtractConfiguration.php
new file mode 100644
index 0000000..6ad0eab
--- /dev/null
+++ b/src/Plugin/migrate/process/ExtractConfiguration.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace Drupal\panelizer\Plugin\migrate\process;
+
+use Drupal\Core\Config\TypedConfigManagerInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\migrate\MigrateExecutableInterface;
+use Drupal\migrate\ProcessPluginBase;
+use Drupal\migrate\Row;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * @MigrateProcessPlugin(
+ *   id = "extract_configuration",
+ * )
+ */
+class ExtractConfiguration extends ProcessPluginBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * @var \Drupal\Core\Config\TypedConfigManagerInterface
+   */
+  protected $typedConfig;
+
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, TypedConfigManagerInterface $typed_config) {
+    $configuration += [
+      'bypass' => TRUE,
+    ];
+    $this->typedConfig = $typed_config;
+
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('config.typed')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function transform($data_type, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
+    $definition = $this->typedConfig->getDefinition($data_type);
+
+    if (isset($definition['mapping'])) {
+      return array_intersect_key($row->getSource(), $definition['mapping']);
+    }
+    elseif ($this->configuration['bypass']) {
+      return $row->getSource();
+    }
+    else {
+      return [];
+    }
+  }
+
+}
diff --git a/src/Plugin/migrate/source/Layout.php b/src/Plugin/migrate/source/Layout.php
new file mode 100644
index 0000000..ee6e4c2
--- /dev/null
+++ b/src/Plugin/migrate/source/Layout.php
@@ -0,0 +1,167 @@
+<?php
+
+namespace Drupal\panelizer\Plugin\migrate\source;
+
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\migrate\Plugin\migrate\source\SourcePluginBase;
+use Drupal\migrate\Plugin\MigrationInterface;
+use Drupal\migrate\Row;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * @MigrateSource(
+ *   id = "panelizer_layout",
+ *   source_module = "panelizer",
+ * )
+ */
+class Layout extends SourcePluginBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The entity view display storage handler.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $storage;
+
+  /**
+   * Layout constructor.
+   *
+   * @param array $configuration
+   *   Plugin configuration.
+   * @param string $plugin_id
+   *   The plugin ID.
+   * @param mixed $plugin_definition
+   *   The plugin definition.
+   * @param \Drupal\migrate\Plugin\MigrationInterface $migration
+   *   The current migration.
+   * @param \Drupal\Core\Entity\EntityStorageInterface $storage
+   *   The entity view display storage handler.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, EntityStorageInterface $storage) {
+    $configuration += [
+      'scope' => 'all',
+    ];
+    $this->storage = $storage;
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $migration,
+      $container->get('entity_type.manager')->getStorage('entity_view_display')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function initializeIterator() {
+    /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display */
+    foreach ($this->storage->loadMultiple() as $display) {
+      $layouts = $display->getThirdPartySetting('panelizer', 'displays', []);
+
+      foreach ($layouts as $id => $layout) {
+        yield [
+          'enable' => $display->getThirdPartySetting('panelizer', 'enable'),
+          'custom' => $display->getThirdPartySetting('panelizer', 'custom'),
+          'default' => $display->getThirdPartySetting('panelizer', 'default'),
+          'id' => $id,
+          'blocks' => $layout['blocks'],
+          'variant' => $layout['id'],
+          'uuid' => $layout['uuid'],
+          'label' => $layout['label'],
+          'weight' => $layout['weight'],
+          'layout' => $layout['layout'],
+          'layout_settings' => $layout['layout_settings'],
+          'page_title' => $layout['page_title'],
+          'storage_type' => $layout['storage_type'],
+          'storage_id' => $layout['storage_id'],
+          'pattern' => $layout['pattern'],
+          'builder' => $layout['builder'],
+          'static_context' => @$layout['static_context'] ?: [],
+          'entity_type' => $display->getTargetEntityTypeId(),
+          'bundle' => $display->getTargetBundle(),
+          'view_mode' => $display->getMode(),
+        ];
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function prepareRow(Row $row) {
+    $is_default = $row->getSourceProperty('id') === $row->getSourceProperty('default');
+
+    if ((! $is_default) && $this->configuration['scope'] === 'default') {
+      return FALSE;
+    }
+    elseif ($is_default && $this->configuration['scope'] === 'not_default') {
+      return FALSE;
+    }
+    return parent::prepareRow($row);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __toString() {
+    return (string) $this->t('All Panelizer layouts stored in entity view displays');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIds() {
+    return [
+      'entity_type' => [
+        'type' => 'string',
+      ],
+      'bundle' => [
+        'type' => 'string',
+      ],
+      'view_mode' => [
+        'type' => 'string',
+      ],
+      'id' => [
+        'type' => 'string',
+      ],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function fields() {
+    return [
+      'enable' => $this->t('Whether or not Panelizer is enabled on the entity view display'),
+      'custom' => $this->t('Whether users are allowed to customize the layout per-entity'),
+      'default' => $this->t('The ID of the default layout in the entity view display'),
+      'id' => $this->t('The ID of the layout'),
+      'blocks' => $this->t('Array of blocks in the layout'),
+      'variant' => $this->t('Plugin ID of the page variant'),
+      'uuid' => $this->t('The UUID of the layout'),
+      'label' => $this->t('The human-readable label of the layout'),
+      'weight' => $this->t('The weight of the layout in the entity view display'),
+      'layout' => $this->t('The plugin ID of the layout'),
+      'layout_settings' => $this->t('Additional settings for the layout plugin'),
+      'page_title' => $this->t('The page title used when content is displayed with the layout (may contain tokens)'),
+      'storage_type' => $this->t('The plugin ID of the storage backend'),
+      'storage_id' => $this->t('The storage backend-specific ID of the layout'),
+      'pattern' => $this->t('The ID of the pattern plugin'),
+      'builder' => $this->t('The ID of the builder plugin'),
+      'static_context' => $this->t('Any static contexts assigned to the layout'),
+      'entity_type' => $this->t('The target entity type ID of the entity view display'),
+      'bundle' => $this->t('The target bundle of the entity view display'),
+      'view_mode' => $this->t('The target view mode of the entity view display'),
+    ];
+  }
+
+}
diff --git a/tests/src/FunctionalJavascript/LayoutBuilderMigrationTest.php b/tests/src/FunctionalJavascript/LayoutBuilderMigrationTest.php
new file mode 100644
index 0000000..a48b3f2
--- /dev/null
+++ b/tests/src/FunctionalJavascript/LayoutBuilderMigrationTest.php
@@ -0,0 +1,123 @@
+<?php
+
+namespace Drupal\Tests\panelizer\FunctionalJavascript;
+
+use Drupal\FunctionalJavascriptTests\DrupalSelenium2Driver;
+use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
+use Drupal\layout_builder\Entity\LayoutEntityDisplayInterface;
+use Drupal\migrate\MigrateExecutable;
+use Drupal\migrate\MigrateMessageInterface;
+use Drupal\migrate\Plugin\MigrationInterface;
+
+/**
+ * Tests migration from Panelizer to Layout Builder.
+ *
+ * @group panelizer
+ */
+class LayoutBuilderMigrationTest extends JavascriptTestBase implements MigrateMessageInterface {
+
+  protected $minkDefaultDriverClass = DrupalSelenium2Driver::class;
+
+  /**
+   * A node type created for testing.
+   *
+   * @var \Drupal\node\NodeTypeInterface
+   */
+  protected $nodeType;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'layout_builder',
+    'migrate',
+    'node',
+    'panelizer',
+    'panels_ipe',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->nodeType = $this->drupalCreateContentType();
+    $this->placeBlock('local_actions_block');
+  }
+
+  protected function runMigration($migration_id, $imported_count = NULL) {
+    /** @var MigrationInterface $migration */
+    $migration = $this->container->get('plugin.manager.migration')
+      ->createInstance($migration_id);
+
+    $executable = new MigrateExecutable($migration, $this);
+    $this->assertSame(MigrationInterface::RESULT_COMPLETED, $executable->import());
+
+    if (isset($imported_count)) {
+      $this->assertSame($imported_count, $migration->getIdMap()->importedCount());
+    }
+    return $migration;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function display($message, $type = 'status') {
+    if ($type == 'error') {
+      $this->fail($message);
+    }
+  }
+
+  public function test() {
+    $this->drupalLogin($this->rootUser);
+    $assert = $this->assertSession();
+
+    $node_type = $this->nodeType->id();
+    $this->drupalGet("/admin/structure/types/manage/$node_type/display");
+    $assert->fieldExists('panelizer[enable]')->check();
+    $assert->buttonExists('Save')->press();
+    $assert->elementExists('named', ['link', 'Edit'])->click();
+    $assert->elementExists('named', ['link', 'Layout'])->click();
+    $assert->fieldExists('Layout')->setValue('layout_twocol');
+    $assert->buttonExists('Change Layout')->press();
+    $assert->fieldExists('blocks[old_content][region]')->setValue('top');
+    $assert->buttonExists('Update and save')->press();
+    $assert->elementExists('named', ['link', 'Content'])->click();
+    $assert->elementExists('named', ['link', 'Add new block'])->click();
+    $assert->waitForElement('css', '#drupal-modal');
+    $assert->elementExists('named', ['link', 'UUID'])->click();
+    $assert->assertWaitOnAjaxRequest();
+    $assert->buttonExists('Add block')->press();
+    $assert->fieldExists('Region for "UUID"')->setValue('bottom');
+    $assert->buttonExists('Update and save')->press();
+
+    $this->runMigration('panelizer_entity_view_display', 1);
+
+    $display = entity_get_display('node', $this->nodeType->id(), 'default');
+    $this->assertInstanceOf(LayoutEntityDisplayInterface::class, $display);
+    /** @var LayoutEntityDisplayInterface $display */
+    $this->assertCount(1, $display);
+    $section = $display->getSection(0);
+    $this->assertSame('layout_twocol', $section->getLayoutId());
+    $this->assertSame([], $section->getLayoutSettings());
+    $components = $section->getComponents();
+    $this->assertCount(4, $components);
+
+    $component = array_shift($components);
+    $this->assertSame('top', $component->getRegion());
+    $this->assertSame('entity_field:node:uid', $component->getPluginId());
+
+    $component = array_shift($components);
+    $this->assertSame('top', $component->getRegion());
+    $this->assertSame('entity_field:node:created', $component->getPluginId());
+
+    $component = array_shift($components);
+    $this->assertSame('top', $component->getRegion());
+    $this->assertSame('entity_field:node:body', $component->getPluginId());
+
+    $component = array_shift($components);
+    $this->assertSame('bottom', $component->getRegion());
+    $this->assertSame('entity_field:node:uuid', $component->getPluginId());
+  }
+
+}
diff --git a/tests/src/Kernel/Plugin/migrate/destination/LayoutSectionTest.php b/tests/src/Kernel/Plugin/migrate/destination/LayoutSectionTest.php
new file mode 100644
index 0000000..6b206bb
--- /dev/null
+++ b/tests/src/Kernel/Plugin/migrate/destination/LayoutSectionTest.php
@@ -0,0 +1,90 @@
+<?php
+
+namespace Drupal\Tests\panelizer\Kernel\Plugin\migrate\destination;
+
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\migrate\Row;
+use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
+
+/**
+ * @coversDefaultClass \Drupal\panelizer\Plugin\migrate\destination\LayoutSection
+ *
+ * @group panelizer
+ */
+class LayoutSectionTest extends KernelTestBase {
+
+  use ContentTypeCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'ctools',
+    'field',
+    'field_ui',
+    'layout_builder',
+    'layout_discovery',
+    'migrate',
+    'node',
+    'panelizer',
+    'panels',
+    'system',
+    'text',
+    'user',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installSchema('system', 'key_value_expire');
+    $this->installConfig('node');
+    $this->createContentType(['type' => 'page']);
+  }
+
+  /**
+   * @covers ::import
+   * @covers ::rollback
+   */
+  public function testImportAndRollback() {
+    /** @var \Drupal\migrate\Plugin\MigrateDestinationInterface $destination */
+    $destination = $this->container->get('plugin.manager.migration')
+      ->createStubMigration([
+        'source' => [
+          'plugin' => 'empty',
+        ],
+        'destination' => [
+          'plugin' => 'layout_section',
+        ],
+      ])
+      ->getDestinationPlugin();
+
+    $row = new Row();
+    $row->setDestinationProperty('entity_type', 'node');
+    $row->setDestinationProperty('bundle', 'page');
+    $row->setDestinationProperty('view_mode', 'full');
+    $row->setDestinationProperty('layout_id', 'layout_onecol');
+    $row->setDestinationProperty('layout_settings', []);
+    $row->setDestinationProperty('components', []);
+
+    $id = $destination->import($row);
+    $this->assertSame('node', $id['entity_type']);
+    $this->assertSame('page', $id['bundle']);
+    $this->assertSame('full', $id['view_mode']);
+
+    /** @var \Drupal\layout_builder\Entity\LayoutEntityDisplayInterface $display */
+    $display = entity_get_display('node', 'page', 'full');
+    $this->assertCount(1, $display);
+    $section = $display->getSection(0);
+    $this->assertSame('layout_onecol', $section->getLayoutId());
+    $this->assertSame([], $section->getLayoutSettings());
+    $this->assertSame([], $section->getComponents());
+
+    $destination->rollback($id);
+
+    $display = entity_get_display('node', 'page', 'full');
+    $this->assertCount(0, $display);
+  }
+
+}
diff --git a/tests/src/Kernel/Plugin/migrate/source/LayoutTest.php b/tests/src/Kernel/Plugin/migrate/source/LayoutTest.php
new file mode 100644
index 0000000..3f6f874
--- /dev/null
+++ b/tests/src/Kernel/Plugin/migrate/source/LayoutTest.php
@@ -0,0 +1,311 @@
+<?php
+
+namespace Drupal\Tests\panelizer\Kernel\Plugin\migrate\source;
+
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
+
+/**
+ * @covers \Drupal\panelizer\Plugin\migrate\source\Layout
+ *
+ * @group panelizer
+ */
+class LayoutTest extends KernelTestBase {
+
+  use ContentTypeCreationTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'ctools',
+    'field',
+    'field_ui',
+    'migrate',
+    'node',
+    'panelizer',
+    'panels',
+    'system',
+    'text',
+    'user',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installConfig('node');
+    $this->createContentType(['type' => 'page']);
+
+    entity_get_display('node', 'page', 'full')
+      ->setThirdPartySetting('panelizer', 'enable', TRUE)
+      ->setThirdPartySetting('panelizer', 'custom', FALSE)
+      ->setThirdPartySetting('panelizer', 'default', 'bar')
+      ->setThirdPartySetting('panelizer', 'displays', [
+        'foo' => [
+          'blocks' => [],
+          'id' => 'panels_variant',
+          'uuid' => 'foo--uuid',
+          'label' => 'Foo',
+          'weight' => 33,
+          'layout' => 'layout_onecol',
+          'layout_settings' => [],
+          'page_title' => '[node:title]',
+          'storage_type' => 'panelizer_default',
+          'storage_id' => 'node:page:full:foo',
+          'pattern' => 'panelizer',
+          'builder' => 'ipe',
+          'static_context' => [],
+        ],
+        'bar' => [
+          'blocks' => [],
+          'id' => 'panels_variant',
+          'uuid' => 'bar--uuid',
+          'label' => 'Bar',
+          'weight' => 99,
+          'layout' => 'layout_twocol',
+          'layout_settings' => [],
+          'page_title' => 'Bar!',
+          'storage_type' => 'panelizer_default',
+          'storage_id' => 'node:page:full:bar',
+          'pattern' => 'panelizer',
+          'builder' => 'ipe',
+          'static_context' => [],
+        ],
+        'baz' => [
+          'blocks' => [],
+          'id' => 'panels_variant',
+          'uuid' => 'baz--uuid',
+          'label' => 'Baz',
+          'weight' => 29,
+          'layout' => 'layout_threecol_25_50_25',
+          'layout_settings' => [],
+          'page_title' => 'Behold, Baz',
+          'storage_type' => 'panelizer_default',
+          'storage_id' => 'node:page:full:baz',
+          'pattern' => 'panelizer',
+          'builder' => 'ipe',
+          'static_context' => [],
+        ],
+      ])
+      ->save();
+  }
+
+  /**
+   * Returns all layouts from the source plugin.
+   *
+   * @param array $configuration
+   *   Configuration for the source plugin.
+   *
+   * @return \Drupal\migrate\Row[]
+   *   The rows returned from the source plugin.
+   */
+  protected function getAll(array $configuration = []) {
+    $configuration['plugin'] = 'panelizer_layout';
+
+    $source = $this->container->get('plugin.manager.migration')
+      ->createStubMigration([
+        'source' => $configuration,
+        'destination' => [
+          'plugin' => 'null',
+        ],
+      ])
+      ->getSourcePlugin();
+
+    return array_filter(iterator_to_array($source), [$source, 'prepareRow']);
+  }
+
+  /**
+   * Tests returning all layouts.
+   */
+  public function testAll() {
+    $layouts = $this->getAll();
+    $this->assertCount(3, $layouts);
+
+    $keys = [
+      [
+        'entity_type' => 'node',
+        'bundle' => 'page',
+        'view_mode' => 'full',
+        'id' => 'foo',
+      ],
+      [
+        'entity_type' => 'node',
+        'bundle' => 'page',
+        'view_mode' => 'full',
+        'id' => 'bar',
+      ],
+      [
+        'entity_type' => 'node',
+        'bundle' => 'page',
+        'view_mode' => 'full',
+        'id' => 'baz',
+      ],
+    ];
+    $this->assertSame(array_map('serialize', $keys), array_keys($layouts));
+
+    $layout = array_shift($layouts)->getSource();
+    $this->assertTrue($layout['enable']);
+    $this->assertFalse($layout['custom']);
+    $this->assertSame('bar', $layout['default']);
+    $this->assertSame('foo', $layout['id']);
+    $this->assertSame([], $layout['blocks']);
+    $this->assertSame('panels_variant', $layout['variant']);
+    $this->assertSame('foo--uuid', $layout['uuid']);
+    $this->assertSame('Foo', $layout['label']);
+    $this->assertSame(33, $layout['weight']);
+    $this->assertSame('layout_onecol', $layout['layout']);
+    $this->assertSame([], $layout['layout_settings']);
+    $this->assertSame('[node:title]', $layout['page_title']);
+    $this->assertSame('panelizer_default', $layout['storage_type']);
+    $this->assertSame('node:page:full:foo', $layout['storage_id']);
+    $this->assertSame('panelizer', $layout['pattern']);
+    $this->assertSame('ipe', $layout['builder']);
+    $this->assertSame([], $layout['static_context']);
+    $this->assertSame('node', $layout['entity_type']);
+    $this->assertSame('page', $layout['bundle']);
+    $this->assertSame('full', $layout['view_mode']);
+
+    $layout = array_shift($layouts)->getSource();
+    $this->assertTrue($layout['enable']);
+    $this->assertFalse($layout['custom']);
+    $this->assertSame('bar', $layout['default']);
+    $this->assertSame('bar', $layout['id']);
+    $this->assertSame([], $layout['blocks']);
+    $this->assertSame('panels_variant', $layout['variant']);
+    $this->assertSame('bar--uuid', $layout['uuid']);
+    $this->assertSame('Bar', $layout['label']);
+    $this->assertSame(99, $layout['weight']);
+    $this->assertSame('layout_twocol', $layout['layout']);
+    $this->assertSame([], $layout['layout_settings']);
+    $this->assertSame('Bar!', $layout['page_title']);
+    $this->assertSame('panelizer_default', $layout['storage_type']);
+    $this->assertSame('node:page:full:bar', $layout['storage_id']);
+    $this->assertSame('panelizer', $layout['pattern']);
+    $this->assertSame('ipe', $layout['builder']);
+    $this->assertSame([], $layout['static_context']);
+
+    $layout = array_shift($layouts)->getSource();
+    $this->assertTrue($layout['enable']);
+    $this->assertFalse($layout['custom']);
+    $this->assertSame('bar', $layout['default']);
+    $this->assertSame('baz', $layout['id']);
+    $this->assertSame([], $layout['blocks']);
+    $this->assertSame('panels_variant', $layout['variant']);
+    $this->assertSame('baz--uuid', $layout['uuid']);
+    $this->assertSame('Baz', $layout['label']);
+    $this->assertSame(29, $layout['weight']);
+    $this->assertSame('layout_threecol_25_50_25', $layout['layout']);
+    $this->assertSame([], $layout['layout_settings']);
+    $this->assertSame('Behold, Baz', $layout['page_title']);
+    $this->assertSame('panelizer_default', $layout['storage_type']);
+    $this->assertSame('node:page:full:baz', $layout['storage_id']);
+    $this->assertSame('panelizer', $layout['pattern']);
+    $this->assertSame('ipe', $layout['builder']);
+    $this->assertSame([], $layout['static_context']);
+  }
+
+  /**
+   * Tests returning only the default layout.
+   */
+  public function testDefault() {
+    $layouts = $this->getAll(['scope' => 'default']);
+    $this->assertCount(1, $layouts);
+
+    $keys = [
+      [
+        'entity_type' => 'node',
+        'bundle' => 'page',
+        'view_mode' => 'full',
+        'id' => 'bar',
+      ],
+    ];
+    $this->assertSame(array_map('serialize', $keys), array_keys($layouts));
+
+    $layout = array_shift($layouts)->getSource();
+    $this->assertTrue($layout['enable']);
+    $this->assertFalse($layout['custom']);
+    $this->assertSame('bar', $layout['default']);
+    $this->assertSame('bar', $layout['id']);
+    $this->assertSame([], $layout['blocks']);
+    $this->assertSame('panels_variant', $layout['variant']);
+    $this->assertSame('bar--uuid', $layout['uuid']);
+    $this->assertSame('Bar', $layout['label']);
+    $this->assertSame(99, $layout['weight']);
+    $this->assertSame('layout_twocol', $layout['layout']);
+    $this->assertSame([], $layout['layout_settings']);
+    $this->assertSame('Bar!', $layout['page_title']);
+    $this->assertSame('panelizer_default', $layout['storage_type']);
+    $this->assertSame('node:page:full:bar', $layout['storage_id']);
+    $this->assertSame('panelizer', $layout['pattern']);
+    $this->assertSame('ipe', $layout['builder']);
+    $this->assertSame([], $layout['static_context']);
+  }
+
+  /**
+   * Tests returning only non-default layouts.
+   */
+  public function testNotDefault() {
+    $layouts = $this->getAll(['scope' => 'not_default']);
+    $this->assertCount(2, $layouts);
+
+    $keys = [
+      [
+        'entity_type' => 'node',
+        'bundle' => 'page',
+        'view_mode' => 'full',
+        'id' => 'foo',
+      ],
+      [
+        'entity_type' => 'node',
+        'bundle' => 'page',
+        'view_mode' => 'full',
+        'id' => 'baz',
+      ],
+    ];
+    $this->assertSame(array_map('serialize', $keys), array_keys($layouts));
+
+    $layout = array_shift($layouts)->getSource();
+    $this->assertTrue($layout['enable']);
+    $this->assertFalse($layout['custom']);
+    $this->assertSame('bar', $layout['default']);
+    $this->assertSame('foo', $layout['id']);
+    $this->assertSame([], $layout['blocks']);
+    $this->assertSame('panels_variant', $layout['variant']);
+    $this->assertSame('foo--uuid', $layout['uuid']);
+    $this->assertSame('Foo', $layout['label']);
+    $this->assertSame(33, $layout['weight']);
+    $this->assertSame('layout_onecol', $layout['layout']);
+    $this->assertSame([], $layout['layout_settings']);
+    $this->assertSame('[node:title]', $layout['page_title']);
+    $this->assertSame('panelizer_default', $layout['storage_type']);
+    $this->assertSame('node:page:full:foo', $layout['storage_id']);
+    $this->assertSame('panelizer', $layout['pattern']);
+    $this->assertSame('ipe', $layout['builder']);
+    $this->assertSame([], $layout['static_context']);
+    $this->assertSame('node', $layout['entity_type']);
+    $this->assertSame('page', $layout['bundle']);
+    $this->assertSame('full', $layout['view_mode']);
+
+    $layout = array_shift($layouts)->getSource();
+    $this->assertTrue($layout['enable']);
+    $this->assertFalse($layout['custom']);
+    $this->assertSame('bar', $layout['default']);
+    $this->assertSame('baz', $layout['id']);
+    $this->assertSame([], $layout['blocks']);
+    $this->assertSame('panels_variant', $layout['variant']);
+    $this->assertSame('baz--uuid', $layout['uuid']);
+    $this->assertSame('Baz', $layout['label']);
+    $this->assertSame(29, $layout['weight']);
+    $this->assertSame('layout_threecol_25_50_25', $layout['layout']);
+    $this->assertSame([], $layout['layout_settings']);
+    $this->assertSame('Behold, Baz', $layout['page_title']);
+    $this->assertSame('panelizer_default', $layout['storage_type']);
+    $this->assertSame('node:page:full:baz', $layout['storage_id']);
+    $this->assertSame('panelizer', $layout['pattern']);
+    $this->assertSame('ipe', $layout['builder']);
+    $this->assertSame([], $layout['static_context']);
+  }
+
+}
