diff --git a/core/modules/layout/lib/Drupal/layout/Config/BoundDisplayInterface.php b/core/modules/layout/lib/Drupal/layout/Config/BoundDisplayInterface.php
new file mode 100644
index 0000000..049d5ef
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Config/BoundDisplayInterface.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\layout\Config\BoundDisplayInterface
+ */
+
+namespace Drupal\layout\Config;
+
+use Drupal\layout\Plugin\LayoutInterface;
+
+interface BoundDisplayInterface extends DisplayInterface {
+
+  /**
+   * Set the layout plugin to be used by this display.
+   *
+   * @param string $plugin_id
+   *   The plugin id of the desired layout plugin.
+   */
+  public function setLayout($plugin_id);
+
+  /**
+   * Returns an indexed array of block config names, sorted by the order in
+   * which they should appear in the region.
+   *
+   * @param string $region
+   *   The region from which to return the set of blocks.
+   *
+   * @return array
+   */
+  public function getSortedBlocksByRegion($region);
+
+  /**
+   * Returns an array of arrays, keyed by region name and containing the
+   * same data as that which is returned by
+   * @see DisplayInterface::getSortedBlocksByRegion().
+   *
+   * @return mixed
+   */
+  public function getAllSortedBlocks();
+
+  /**
+   * Returns the layout plugin instance to be used with this display.
+   *
+   * @return \Drupal\layout\Plugin\LayoutInterface
+   */
+  public function getLayoutPluginInstance();
+
+  /**
+   * Perform block remapping per mapBlocksToLayout(), but mutate this object
+   * with the remapping results instead of returning them.
+   *
+   * @see \Drupal\layout\Config\DisplayBase::mapBlocksToLayout()
+   *
+   * @param \Drupal\layout\Plugin\LayoutInterface $layout
+   */
+  public function remapToLayout(LayoutInterface $layout);
+
+  /**
+   * Returns an UnboundDisplay by stripping out the layout and region-specific
+   * bindings on this object.
+   *
+   * @param string $id
+   *   The id that will be used to uniquely identify the created UnboundDisplay.
+   *   It will be appended to the config prefix for Displays ("display.unbound",
+   *   unless altered) to form the new Display's config address.
+   *
+   * @param string $entity_type
+   *   The type of entity to create. Must resolve to a class implementing
+   *   UnboundDisplayInterface.
+   *
+   * @return \Drupal\layout\Config\UnboundDisplayInterface
+   *   The newly-created UnboundDisplay.
+   */
+  public function generateUnboundDisplay($id, $entity_type = 'unbound_display');
+}
diff --git a/core/modules/layout/lib/Drupal/layout/Config/DisplayBase.php b/core/modules/layout/lib/Drupal/layout/Config/DisplayBase.php
new file mode 100644
index 0000000..95c07bb
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Config/DisplayBase.php
@@ -0,0 +1,130 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\layout\Config\DisplayBase.
+ */
+
+namespace Drupal\layout\Config;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\layout\Plugin\LayoutInterface;
+
+/**
+ * Configuration encapsulator that provides all the data needed by block-driven
+ * controllers to render a page.
+ *
+ * This is an abstract parent containing functionality shared by both Display
+ * and UnboundDisplay config objects.
+ */
+abstract class DisplayBase extends ConfigEntityBase implements DisplayInterface {
+
+  /**
+   * The ID (config name) identifying a specific display object.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The UUID identifying a specific display object.
+   *
+   * @var string
+   */
+  public $uuid;
+
+  /**
+   * Contains all block configuration.
+   *
+   * There are two levels to the configuration contained herein: display-level
+   * block configuration, and then block instance configuration.
+   *
+   * Block instance configuration is stored in a separate config object. This
+   * array is keyed by the config name that uniquely identifies each block
+   * instance. At runtime, various object methods will retrieve this additional
+   * config and return it to calling code.
+   *
+   * Display-level block configuration is data that determines the behavior of
+   * a block *in this display*. The most important examples of this are the
+   * region to which the block is assigned, and its weighting in that region.
+   *
+   * @code
+   *    array(
+   *      'block1-configkey' => array(
+   *        'region' => 'content',
+   *        // store the region type name here so that we can do type conversion w/out
+   *        // needing to have access to the original layout plugin
+   *        'region-type' => 'content',
+   *        // increment by 100 so there is ALWAYS plenty of space for manual insertion
+   *        'weight' => -100,
+   *      ),
+   *      'block2-configkey' => array(
+   *        'region' => 'sidebar_first',
+   *        'region-type' => 'aside',
+   *        'weight' => -100,
+   *      ),
+   *      'block2-configkey' => array(
+   *        'region' => 'sidebar_first',
+   *        'region-type' => 'aside',
+   *        'weight' => 0,
+   *      ),
+   *      'maincontent' => array(
+   *        'region' => 'content',
+   *        'region-type' => 'content',
+   *        'weight' => -200,
+   *      ),
+   *    );
+   * @endcode
+   *
+   * @var array
+   */
+  protected $blockInfo = array();
+
+  /**
+   * Implements DisplayInterface::getAllBlockInfo().
+   *
+   * @return array
+   */
+  public function getAllBlockInfo() {
+    return $this->blockInfo;
+  }
+
+  /**
+   * Implements DisplayInterface::mapBlocksToLayout().
+   *
+   * @todo this logic ought not be tightly coupled to this class.
+   *
+   * @param \Drupal\layout\Plugin\LayoutInterface $layout
+   *
+   * @return array
+   */
+  public function mapBlocksToLayout(LayoutInterface $layout) {
+    $types = array();
+
+    $layout_regions = $layout->getRegions();
+    $layout_regions_indexed = array_keys($layout_regions);
+    foreach ($layout_regions as $name => $info) {
+      $types[$info['type']][] = $name;
+    }
+
+    $remapped_config = array();
+    foreach ($this->blockInfo as $name => $info) {
+      // First, if there's a direct region name match, use that.
+      if (!empty($info['region']) && isset($layout_regions[$info['region']])) {
+        // No need to do anything.
+      }
+      // Then, try to remap using region types.
+      else if (!empty($types[$info['region-type']])) {
+        $info['region'] = reset($types[$info['region-type']]);
+      }
+      // Finally, fall back to dumping everything in the layout's first region.
+      else {
+        $info['region'] = reset($layout_regions_indexed);
+      }
+
+      $remapped_config[$name] = $info;
+    }
+
+    return $remapped_config;
+  }
+}
diff --git a/core/modules/layout/lib/Drupal/layout/Config/DisplayInterface.php b/core/modules/layout/lib/Drupal/layout/Config/DisplayInterface.php
new file mode 100644
index 0000000..1337077
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Config/DisplayInterface.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\layout\Config\DisplayInterface
+ */
+
+namespace Drupal\layout\Config;
+
+use Drupal\layout\Plugin\LayoutInterface;
+
+interface DisplayInterface {
+
+  /**
+   * Returns the config info about all blocks on this display.
+   *
+   * There are two levels of configuration that are being captured here: the
+   * configuration for the block itself (i.e., config generated by a user saving
+   * the block's edit form), and configuration for how the particular block
+   * instance behaves in *this* display. The former is typically its own config
+   * object, and only a reference to that config key is stored directly on this
+   * object. The most important examples of the latter are the region in which
+   * the block is placed, and its weighting within the region.
+   *
+   * @return array
+   *   An array of block info, keyed on each block's config name.
+   */
+  public function getAllBlockInfo();
+
+  /**
+   * Map the contained block info to the provided layout.
+   *
+   * @param \Drupal\layout\Plugin\LayoutInterface $layout
+   *
+   * @return array
+   *   An array containing block configuration info, identical to that which
+   *   is returned by DisplayInterface::getAllBlockInfo().
+   */
+  public function mapBlocksToLayout(LayoutInterface $layout);
+}
diff --git a/core/modules/layout/lib/Drupal/layout/Config/UnboundDisplayInterface.php b/core/modules/layout/lib/Drupal/layout/Config/UnboundDisplayInterface.php
new file mode 100644
index 0000000..d709db1
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Config/UnboundDisplayInterface.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\layout\Config\UnboundDisplayInterface
+ */
+
+namespace Drupal\layout\Config;
+
+use Drupal\layout\Plugin\LayoutInterface;
+
+interface UnboundDisplayInterface extends DisplayInterface {
+  /**
+   * Bind this UnboundDisplay to a particular display.
+   *
+   * This will DisplayInterface::mapBlocksToLayout() using the provided layout,
+   * then create and return a new Display object with the output. This is just
+   * a factory - calling code is responsible for saving the
+   *
+   * @param \Drupal\layout\Plugin\LayoutInterface $layout
+   *   The layout plugin to which this config object should be bound.
+   *
+   * @param string $id
+   *   The id that will be used to uniquely identify the created Display. It
+   *   will be appended to the config prefix for Displays ("display", unless
+   *   altered) to form the new Display's config address.
+   *
+   * @param string $entity_type
+   *   The type of entity to create. Must resolve to a class implementing
+   *   BoundDisplayInterface.
+   *
+   * @return \Drupal\layout\Plugin\Core\Entity\Display
+   *   A Display object that has had the data from this config object mapped to
+   *   the provided layout plugin.
+   */
+  public function generateDisplay(LayoutInterface $layout, $id, $entity_type = 'display');
+}
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/Display.php b/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/Display.php
new file mode 100644
index 0000000..3014657
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/Display.php
@@ -0,0 +1,194 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\layout\Plugin\Core\Entity\Display.
+ */
+
+namespace Drupal\layout\Plugin\Core\Entity;
+
+use Drupal\layout\Config\DisplayBase;
+use Drupal\layout\Config\BoundDisplayInterface;
+use Drupal\layout\Config\UnboundDisplayInterface;
+use Drupal\layout\Plugin\LayoutInterface;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Configuration encapsulator that provides all the data needed by block-driven
+ * controllers to render a page.
+ *
+ * @Plugin(
+ *   id = "display",
+ *   label = @Translation("Display"),
+ *   module = "layout",
+ *   controller_class = "Drupal\Core\Config\Entity\ConfigStorageController",
+ *   config_prefix = "display.bound",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "uuid" = "uuid"
+ *   }
+ * )
+ */
+class Display extends DisplayBase implements BoundDisplayInterface {
+  /**
+   * A two-level array expressing block ordering within regions.
+   *
+   * The outer array is associative, keyed on region name. Each inner array is
+   * indexed, with the config address of a block as values and sorted according
+   * to order in which those blocks should appear in that region.
+   *
+   * This property is not stored statically in config, but is derived at runtime
+   * by DisplayBase::sortBlocks(). It is not stored statically because that
+   * would make using weights for ordering more difficult, and weights make
+   * external mass manipulation of displays much easier.
+   *
+   * @var array
+   */
+  protected $blocksInRegions;
+
+  /**
+   * The layout plugin instance being used to serve this page.
+   *
+   * @var \Drupal\layout\Plugin\LayoutInterface
+   */
+  protected $layoutPlugin;
+
+  /**
+   * The name of the layout plugin to use.
+   *
+   * @var string
+   */
+  public $layout;
+
+  /**
+   * An array of settings to be coupled with the layout plugin to create a
+   * layout plugin instance.
+   *
+   * @var array
+   *
+   * @todo we might possibly want to separate this into its own config object
+   */
+  public $layoutSettings = array();
+
+  /**
+   * Implements BoundDisplayInterface::getSortedBlocksByRegion().
+   *
+   * @param string $region
+   *
+   * @return array
+   * @throws \Exception
+   */
+  public function getSortedBlocksByRegion($region) {
+    if ($this->blocksInRegions === NULL) {
+      $this->sortBlocks();
+    }
+
+    if (!isset($this->blocksInRegions[$region])) {
+      throw new \Exception(sprintf("Region %region does not exist in layout %layout", array('%region' => $region, '%layout' => $this->getLayoutPluginInstance()->name)), E_RECOVERABLE_ERROR);
+    }
+
+    return $this->blocksInRegions[$region];
+  }
+
+  /**
+   * Implements BoundDisplayInterface::getAllSortedBlocks().
+   *
+   * @return array|mixed
+   */
+  public function getAllSortedBlocks() {
+    if ($this->blocksInRegions === NULL) {
+      $this->sortBlocks();
+    }
+
+    return $this->blocksInRegions;
+  }
+
+  /**
+   * Transform the stored blockConfig into a sorted, region-oriented array.
+   */
+  protected function sortBlocks() {
+    $layout_instance = $this->getLayoutPluginInstance();
+    if ($this->layout !== $layout_instance->getPluginId()) {
+      $block_config = $this->mapBlocksToLayout($layout_instance);
+    }
+    else {
+      $block_config = $this->blockInfo;
+    }
+
+    $this->blocksInRegions = array();
+
+    $regions = array_fill_keys(array_keys($layout_instance->getRegions()), array());
+    foreach ($block_config as $config_name => $info) {
+      $regions[$info['region']][$config_name] = $info;
+    }
+
+    foreach ($regions as $region_name => &$blocks) {
+      uasort($blocks, 'drupal_sort_weight');
+      $this->blocksInRegions[$region_name] = array_keys($blocks);
+    }
+  }
+
+  /**
+   * Perform block remapping per mapBlocksToLayout(), but mutate this object
+   * with the remapping results instead of returning them.
+   *
+   * @see \Drupal\layout\Config\DisplayBase::mapBlocksToLayout()
+   *
+   * @param \Drupal\layout\Plugin\LayoutInterface $layout
+   */
+  public function remapToLayout(LayoutInterface $layout) {
+    $this->blockInfo = $this->mapBlocksToLayout($layout);
+    $this->setLayout($layout->getPluginId());
+  }
+
+  /**
+   * Set the contained layout plugin.
+   *
+   * @param string $plugin_id
+   *   The plugin id of the desired layout plugin.
+   */
+  public function setLayout($plugin_id) {
+    // @todo verification?
+    $this->layout = $plugin_id;
+    $this->layoutPlugin = NULL;
+    $this->blocksInRegions = NULL;
+  }
+
+  /**
+   * Implements BoundDisplayInterface::generateUnboundDisplay().
+   *
+   * @throws \Exception
+   */
+  public function generateUnboundDisplay($id, $entity_type = 'unbound_display') {
+    $block_info = $this->getAllBlockInfo();
+    foreach ($block_info as &$info) {
+      unset ($info['region']);
+    }
+
+    $values = array(
+      'blockInfo' => $block_info,
+      'id' => $id,
+    );
+
+    $entity = entity_create($entity_type, $values);
+    if (!$entity instanceof UnboundDisplayInterface) {
+      throw new \Exception(sprintf('Attempted to create an unbound display using an invalid entity type.'), E_RECOVERABLE_ERROR);
+    }
+
+    return $entity;
+  }
+
+  public function getLayoutPluginInstance() {
+    if ($this->layoutPlugin === NULL) {
+      if (empty($this->layout)) {
+        throw new \Exception(sprintf('Display "%id" had no layout plugin attached.', array('%id' => $this->id())), E_RECOVERABLE_ERROR);
+      }
+
+      $this->layoutPlugin = layout_manager()->createInstance($this->layout, $this->layoutSettings);
+      // @todo add handling for remapping if the layout could not be found
+    }
+
+    return $this->layoutPlugin;
+  }
+}
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/UnboundDisplay.php b/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/UnboundDisplay.php
new file mode 100644
index 0000000..0db5871
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/Core/Entity/UnboundDisplay.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\layout\Plugin\Core\Entity\Display.
+ */
+
+namespace Drupal\layout\Plugin\Core\Entity;
+
+use Drupal\layout\Config\DisplayBase;
+use Drupal\layout\Config\BoundDisplayInterface;
+use Drupal\layout\Config\UnboundDisplayInterface;
+use Drupal\layout\Plugin\LayoutInterface;
+use Drupal\Core\Annotation\Plugin;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Configuration encapsulator that provides all the data needed by block-driven
+ * controllers to render a page.
+ *
+ * Unbound displays contain blocks that are not 'bound' to a specific layout,
+ * and their contained blocks are mapped only to region types, not real regions.
+ *
+ * @Plugin(
+ *   id = "unbound_display",
+ *   label = @Translation("Unbound Display"),
+ *   module = "layout",
+ *   controller_class = "Drupal\Core\Config\Entity\ConfigStorageController",
+ *   config_prefix = "display.unbound",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "uuid" = "uuid"
+ *   }
+ * )
+ */
+class UnboundDisplay extends DisplayBase implements UnboundDisplayInterface {
+
+  /**
+   * Implements UnboundDisplayInterface::generateDisplay().
+   *
+   * @throws \Exception
+   */
+  public function generateDisplay(LayoutInterface $layout, $id, $entity_type = 'display') {
+    $values = array(
+      'layout' => $layout->getPluginId(),
+      'blockInfo' => $this->mapBlocksToLayout($layout),
+      'id' => $id,
+    );
+
+    $entity = entity_create($entity_type, $values);
+
+    if (!$entity instanceof BoundDisplayInterface) {
+      throw new \Exception(sprintf('Attempted to bind an unbound display but provided an invalid entity type.'), E_RECOVERABLE_ERROR);
+    }
+
+    return $entity;
+  }
+}
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/LayoutInterface.php b/core/modules/layout/lib/Drupal/layout/Plugin/LayoutInterface.php
index 5b874f6..7521c57 100644
--- a/core/modules/layout/lib/Drupal/layout/Plugin/LayoutInterface.php
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/LayoutInterface.php
@@ -7,10 +7,12 @@
 
 namespace Drupal\layout\Plugin;
 
+use Drupal\Component\Plugin\PluginInspectionInterface;
+
 /**
  * Defines the shared interface for all layout plugins.
  */
-interface LayoutInterface {
+interface LayoutInterface extends PluginInspectionInterface {
 
   /**
    * Returns a list of regions.
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php b/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php
index 4819595..3ded379 100644
--- a/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/layout/layout/StaticLayout.php
@@ -88,11 +88,11 @@ public function renderLayout($admin = FALSE) {
     );
 
     // Render all regions needed for this layout.
-    foreach ($this->getRegions() as $region => $title) {
+    foreach ($this->getRegions() as $region => $info) {
       // @todo This is just stub code to fill in regions with stuff for now.
       // When blocks are related to layouts and not themes, we can make this
       // really be filled in with blocks.
-      $build['#content'][$region] = '<h3>' . $title . '</h3>';
+      $build['#content'][$region] = '<h3>' . $info['label'] . '</h3>';
     }
 
     // Fill in attached CSS and JS files based on metadata.
diff --git a/core/modules/layout/lib/Drupal/layout/Tests/DisplayInternalLogicTest.php b/core/modules/layout/lib/Drupal/layout/Tests/DisplayInternalLogicTest.php
new file mode 100644
index 0000000..9417a32
--- /dev/null
+++ b/core/modules/layout/lib/Drupal/layout/Tests/DisplayInternalLogicTest.php
@@ -0,0 +1,137 @@
+<?php
+
+/**
+ * @file
+ * Definition of \Drupal\layout\Tests\DisplayInternalLogicTest.
+ */
+
+namespace Drupal\layout\Tests;
+
+use Drupal\simpletest\WebTestBase;
+use Drupal\layout\Plugin\Core\Entity\Display;
+use Drupal\layout\Plugin\Core\Entity\UnboundDisplay;
+
+/**
+ * Tests the API and internal logic offered by Displays.
+ *
+ * @todo try to make this a UnitTestCase - need config and (for now) module enablement
+ */
+class DisplayInternalLogicTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('layout', 'layout_test');
+
+  /**
+   * The twocol test display.
+   *
+   * @var \Drupal\layout\Plugin\Core\Entity\Display
+   */
+  public $twocol;
+
+  /**
+   * The onecol test display.
+   *
+   * @var \Drupal\layout\Plugin\Core\Entity\Display
+   */
+  public $onecol;
+
+  /**
+   * The unbound test display.
+   *
+   * @var \Drupal\layout\Plugin\Core\Entity\UnboundDisplay
+   */
+  public $unbound;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Display behaviors',
+      'description' => 'Tests internal behaviors of DisplayInterface implementations, such as layout remapping.',
+      'group' => 'Display',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp();
+    $this->twocol = entity_load('display', 'test_twocol');
+    $this->onecol = entity_load('display', 'test_onecol');
+    $this->unbound = entity_load('unbound_display', 'test_unbound_display');
+  }
+
+  /**
+   * Test Display's internal logic for sorting blocks into their respective
+   * regions.
+   */
+  public function testBlockSorting() {
+    $left = $this->twocol->getSortedBlocksByRegion('left');
+    $this->assertEqual(count($left), 2, 'Two blocks found in left region.');
+    list($first, $second) = $left;
+    $this->assertIdentical($first, 'plugin.core.block.test_navigation_instance2');
+    $this->assertIdentical($second, 'plugin.core.block.test_main_block');
+
+    $right = $this->twocol->getSortedBlocksByRegion('right');
+    $this->assertEqual(count($right), 1, 'One block found in right region.');
+    $this->assertIdentical(reset($right), 'plugin.core.block.test_navigation_instance', 'test_navigation_instance block instance is the only block in the right region.');
+
+    $all = $this->twocol->getAllSortedBlocks();
+    $this->assertEqual(count($all), 2, 'Block sorting produces exactly two regions.');
+  }
+
+  /**
+   * Test the various block remapping scenarios allowed for by the assorted
+   * Display types.
+   *
+   * This includes remapping a Display's blocks to a new layout, binding an
+   * UnboundDisplay with a layout to generate a new Display, and releasing a
+   * Display from its layout binding to generate an UnboundDisplay.
+   */
+  public function testBlockMapping() {
+    // First, remap from the twocol to onecol.
+    $two_to_one = clone($this->twocol);
+    $two_to_one->remapToLayout($this->onecol->getLayoutPluginInstance());
+    $middle = $two_to_one->getSortedBlocksByRegion('middle');
+    $this->assertEqual(count($middle), 3, 'Two-to-one correctly has three blocks in its only region.');
+    list($first, $second, $third) = $middle;
+
+    // @todo the determining factors for which of the nav instances comes first is twisty. improve it.
+    $this->assertIdentical($first, 'plugin.core.block.test_navigation_instance2');
+    $this->assertIdentical($second, 'plugin.core.block.test_navigation_instance');
+    $this->assertIdentical($third, 'plugin.core.block.test_main_block');
+
+    // Now, remap from the onecol to twocol.
+    $one_to_two = clone($this->onecol);
+    $one_to_two->remapToLayout($this->twocol->getLayoutPluginInstance());
+
+    $this->assertEqual(count($one_to_two->getAllSortedBlocks()), 2, 'getAllSortedBlocks() returns two regions even though one is empty after onecol to twocol remapping.');
+    list($first, $second) = $one_to_two->getSortedBlocksByRegion('left');
+    $this->assertIdentical($first, 'plugin.core.block.test_navigation_instance');
+    $this->assertIdentical($second, 'plugin.core.block.test_main_block');
+    // Make sure we have an empty right region - no surprises!
+    $this->assertIdentical($one_to_two->getSortedBlocksByRegion('right'), array(), 'Region with no blocks comes back from getSortedBlocksByRegion() as an empty array.');
+
+    // Now, bind the unbound display to the twocol layout.
+    $unbound_to_twocol = $this->unbound->generateDisplay($this->twocol->getLayoutPluginInstance(), 'unbound_to_twocol');
+    $this->assertTrue($unbound_to_twocol instanceof Display, 'Binding the unbound display successfully created a Display object');
+    $left = $unbound_to_twocol->getSortedBlocksByRegion('left');
+    list($first, $second) = $left;
+    $this->assertIdentical($first, 'plugin.core.block.test_main_block');
+    $this->assertIdentical($second, 'plugin.core.block.test_navigation_instance2');
+
+    // Finally, generate an unbound display from the twocol display.
+    $twocol_to_unbound = $this->twocol->generateUnboundDisplay('twocol_to_unbound');
+    $this->assertTrue($twocol_to_unbound instanceof UnboundDisplay, 'Unbinding the twocol display successfully created an UnboundDisplay object');
+
+    // Have to just interrogate the array manually.
+    $blocks_info = $twocol_to_unbound->getAllBlockInfo();
+    foreach ($blocks_info as $address => $info) {
+      $this->assertTrue(empty($info['region']), sprintf('Block info for block %address has no region associated with it.', array('%address' => $address)));
+    }
+
+    $this->assertIdentical($blocks_info['plugin.core.block.test_main_block']['region-type'], 'content');
+    $this->assertIdentical($blocks_info['plugin.core.block.test_navigation_instance']['region-type'], 'aside');
+    $this->assertIdentical($blocks_info['plugin.core.block.test_navigation_instance2']['region-type'], 'content');
+  }
+}
diff --git a/core/modules/layout/tests/config/display.bound.test_onecol.yml b/core/modules/layout/tests/config/display.bound.test_onecol.yml
new file mode 100644
index 0000000..dda0342
--- /dev/null
+++ b/core/modules/layout/tests/config/display.bound.test_onecol.yml
@@ -0,0 +1,14 @@
+id: test_onecol
+label: Onecol testing display
+layout: static_layout:layout_test__one-col
+layoutSettings: { }
+staticData: { }
+blockInfo:
+  plugin.core.block.test_main_block:
+    region: middle
+    region-type: content
+    weight: 100
+  plugin.core.block.test_navigation_instance:
+    region: middle
+    region-type: content
+    weight: -100
diff --git a/core/modules/layout/tests/config/display.bound.test_twocol.yml b/core/modules/layout/tests/config/display.bound.test_twocol.yml
new file mode 100644
index 0000000..fefe355
--- /dev/null
+++ b/core/modules/layout/tests/config/display.bound.test_twocol.yml
@@ -0,0 +1,18 @@
+id: test_twocol
+label: Twocol testing display
+layout: static_layout:layout_test_theme__two-col
+layoutSettings: { }
+staticData: { }
+blockInfo:
+  plugin.core.block.test_main_block:
+    region: left
+    region-type: content
+    weight: 100
+  plugin.core.block.test_navigation_instance:
+    region: right
+    region-type: aside
+    weight: -100
+  plugin.core.block.test_navigation_instance2:
+    region: left
+    region-type: content
+    weight: -100
\ No newline at end of file
diff --git a/core/modules/layout/tests/config/display.unbound.test_unbound_display.yml b/core/modules/layout/tests/config/display.unbound.test_unbound_display.yml
new file mode 100644
index 0000000..db8c8fc
--- /dev/null
+++ b/core/modules/layout/tests/config/display.unbound.test_unbound_display.yml
@@ -0,0 +1,14 @@
+id: test_unbound_display
+label: Unbound display test
+layoutSettings: { }
+staticData: { }
+blockInfo:
+  plugin.core.block.test_main_block:
+    region-type: content
+    weight: -100
+  plugin.core.block.test_navigation_instance:
+    region-type: aside
+    weight: -100
+  plugin.core.block.test_navigation_instance2:
+    region-type: nav
+    weight: 0
\ No newline at end of file
diff --git a/core/modules/layout/tests/config/plugin.core.block.test_main_block.yml b/core/modules/layout/tests/config/plugin.core.block.test_main_block.yml
new file mode 100644
index 0000000..de31170
--- /dev/null
+++ b/core/modules/layout/tests/config/plugin.core.block.test_main_block.yml
@@ -0,0 +1,18 @@
+id: system_main_block
+status: '1'
+cache: '-1'
+visibility:
+  path:
+    visibility: '0'
+    pages: ''
+  role:
+    roles: {  }
+  node_type:
+    types:
+      article: '0'
+      page: '0'
+  visibility__active_tab: edit-visibility-path
+subject: 'main content'
+module: system
+region: content
+weight: '0'
diff --git a/core/modules/layout/tests/config/plugin.core.block.test_navigation_instance.yml b/core/modules/layout/tests/config/plugin.core.block.test_navigation_instance.yml
new file mode 100644
index 0000000..c833f42
--- /dev/null
+++ b/core/modules/layout/tests/config/plugin.core.block.test_navigation_instance.yml
@@ -0,0 +1,18 @@
+id: 'system_menu_block:navigation'
+status: '1'
+cache: '-1'
+visibility:
+  path:
+    visibility: '0'
+    pages: ''
+  role:
+    roles: {  }
+  node_type:
+    types:
+      article: '0'
+      page: '0'
+  visibility__active_tab: edit-visibility-path
+subject: Navigation
+module: system
+region: sidebar_first
+weight: '0'
diff --git a/core/modules/layout/tests/config/plugin.core.block.test_navigation_instance2.yml b/core/modules/layout/tests/config/plugin.core.block.test_navigation_instance2.yml
new file mode 100644
index 0000000..c833f42
--- /dev/null
+++ b/core/modules/layout/tests/config/plugin.core.block.test_navigation_instance2.yml
@@ -0,0 +1,18 @@
+id: 'system_menu_block:navigation'
+status: '1'
+cache: '-1'
+visibility:
+  path:
+    visibility: '0'
+    pages: ''
+  role:
+    roles: {  }
+  node_type:
+    types:
+      article: '0'
+      page: '0'
+  visibility__active_tab: edit-visibility-path
+subject: Navigation
+module: system
+region: sidebar_first
+weight: '0'
diff --git a/core/modules/layout/tests/layout_test.module b/core/modules/layout/tests/layout_test.module
index 36c3915..07e6d3c 100644
--- a/core/modules/layout/tests/layout_test.module
+++ b/core/modules/layout/tests/layout_test.module
@@ -26,7 +26,9 @@ function layout_test_page() {
   global $theme;
   $theme = 'layout_test_theme';
   theme_enable(array($theme));
-  $layout = layout_manager()->createInstance('static_layout:layout_test_theme__two-col');
+  $display = entity_load('display', 'test_twocol');
+  $layout = $display->getLayoutPluginInstance();
+  // @todo this implementation ignores blocks completely, so is inherently incomplete.
   return $layout->renderLayout();
 }
 
diff --git a/core/modules/layout/tests/layouts/static/one-col/one-col.yml b/core/modules/layout/tests/layouts/static/one-col/one-col.yml
index 27d7d06..9048e14 100644
--- a/core/modules/layout/tests/layouts/static/one-col/one-col.yml
+++ b/core/modules/layout/tests/layouts/static/one-col/one-col.yml
@@ -2,4 +2,6 @@ title: Single column
 category: Columns: 1
 template: one-col
 regions:
-  middle: 'Middle column'
+  middle:
+    label: Middle column
+    type: content
diff --git a/core/modules/layout/tests/themes/layout_test_theme/layouts/static/two-col/two-col.yml b/core/modules/layout/tests/themes/layout_test_theme/layouts/static/two-col/two-col.yml
index 7ee126f..01b9e86 100644
--- a/core/modules/layout/tests/themes/layout_test_theme/layouts/static/two-col/two-col.yml
+++ b/core/modules/layout/tests/themes/layout_test_theme/layouts/static/two-col/two-col.yml
@@ -4,5 +4,9 @@ template: two-col
 stylesheets:
   - two-col.css
 regions:
-  left: 'Left side'
-  right: 'Right side'
+  left:
+    label: Left side
+    type: content
+  right:
+    label: Right side
+    type: aside
\ No newline at end of file
