diff --git a/panels.info.yml b/panels.info.yml
index 0778575..741db19 100644
--- a/panels.info.yml
+++ b/panels.info.yml
@@ -7,3 +7,4 @@ core: 8.x
 configure: panels.admin
 dependencies:
   - page_manager
+  - layout_plugin
diff --git a/panels.layouts.yml b/panels.layouts.yml
new file mode 100644
index 0000000..c2fa131
--- /dev/null
+++ b/panels.layouts.yml
@@ -0,0 +1,27 @@
+onecol:
+  label: Single column
+  category: Columns: 1
+  type: page
+  path: plugins/layouts/onecol
+  # @todo Add support for icon: https://www.drupal.org/node/2326595
+  icon: onecol.png
+  css: onecol.css
+  theme: panels_onecol
+  regions:
+    middle:
+      label: Middle column
+
+twocol:
+  label: Two column
+  category: Columns: 2
+  type: page
+  path: plugins/layouts/twocol
+  # @todo Add support for icon: https://www.drupal.org/node/2326595
+  icon: twocol.png
+  css: twocol.css
+  theme: panels_twocol
+  regions:
+    left:
+      label: Left side
+    right:
+      label: Right side
diff --git a/panels.module b/panels.module
index 4bb3bad..ce48f80 100644
--- a/panels.module
+++ b/panels.module
@@ -30,12 +30,45 @@ function panels_api_version() {
  * Implementation of hook_theme()
  */
 function panels_theme() {
-  // Safety: go away if CTools is not at an appropriate version.
-  if (!module_invoke('ctools', 'api_version', PANELS_REQUIRED_CTOOLS_API)) {
-    return array();
+  $theme = array();
+
+  // For now, we register these theme functions manually.
+  // @todo: Reimplement the code below to auto register the theme functions
+  //        with current layout plugins.
+  $theme['panels_onecol'] = array(
+    'render element' => 'content',
+    'path' => drupal_get_path('module', 'panels') . '/plugins/layouts/onecol',
+    'template' => 'panels-onecol',
+  );
+  $theme['panels_twocol'] = array(
+    'render element' => 'content',
+    'path' => drupal_get_path('module', 'panels') . '/plugins/layouts/twocol',
+    'template' => 'panels-twocol',
+  );
+
+  /*
+  $layouts = panels_get_layouts();
+  foreach ($layouts as $name => $data) {
+    foreach (array('theme', 'admin theme') as $callback) {
+      if (!empty($data[$callback])) {
+        $theme[$data[$callback]] = array(
+          'variables' => array('css_id' => NULL, 'content' => NULL, 'settings' => NULL, 'display' => NULL, 'layout' => NULL, 'renderer' => NULL),
+          'path' => $data['path'],
+          'file' => $data['file'],
+        );
+
+        // if no theme function exists, assume template.
+        if (!function_exists("theme_$data[theme]")) {
+          $theme[$data[$callback]]['template'] = str_replace('_', '-', $data[$callback]);
+          $theme[$data[$callback]]['file'] = $data['file']; // for preprocess.
+        }
+      }
+    }
   }
+  */
 
-  $theme = array();
+  // @todo: Port the follow to Drupal 8!
+  /*
   $theme['panels_layout_link'] = array(
     'variables' => array('title' => NULL, 'id' => NULL, 'image' => NULL, 'link' => NULL, 'class' => NULL),
   );
@@ -99,27 +132,6 @@ function panels_theme() {
   // Register layout and style themes on behalf of all of these items.
   ctools_include('plugins', 'panels');
 
-  // No need to worry about files; the plugin has to already be loaded for us
-  // to even know what the theme function is, so files will be auto included.
-  $layouts = panels_get_layouts();
-  foreach ($layouts as $name => $data) {
-    foreach (array('theme', 'admin theme') as $callback) {
-      if (!empty($data[$callback])) {
-        $theme[$data[$callback]] = array(
-          'variables' => array('css_id' => NULL, 'content' => NULL, 'settings' => NULL, 'display' => NULL, 'layout' => NULL, 'renderer' => NULL),
-          'path' => $data['path'],
-          'file' => $data['file'],
-        );
-
-        // if no theme function exists, assume template.
-        if (!function_exists("theme_$data[theme]")) {
-          $theme[$data[$callback]]['template'] = str_replace('_', '-', $data[$callback]);
-          $theme[$data[$callback]]['file'] = $data['file']; // for preprocess.
-        }
-      }
-    }
-  }
-
   $styles = panels_get_styles();
   foreach ($styles as $name => $data) {
     if (!empty($data['render pane'])) {
@@ -146,6 +158,7 @@ function panels_theme() {
       }
     }
   }
+  */
 
   return $theme;
 }
diff --git a/plugins/layouts/onecol/panels-onecol.html.twig b/plugins/layouts/onecol/panels-onecol.html.twig
new file mode 100644
index 0000000..0906cd7
--- /dev/null
+++ b/plugins/layouts/onecol/panels-onecol.html.twig
@@ -0,0 +1,19 @@
+{#
+/**
+ * @file
+ * Template for a 3 column panel layout.
+ *
+ * This template provides a very simple "one column" panel display layout.
+ *
+ * Variables:
+ * - $id: An optional CSS id to use for the layout.
+ * - $content: An array of content, each item in the array is keyed to one
+ *   panel of the layout. This layout supports the following sections:
+ *   $content['middle']: The only panel in the layout.
+ */
+#}
+<div class="panel-display panel-1col clearfix" {% if css_id %}{{ css_id }}{% endif %}>
+  <div class="panel-panel panel-col">
+    <div>{{ content.middle }}</div>
+  </div>
+</div>
diff --git a/plugins/layouts/onecol/panels-onecol.tpl.php b/plugins/layouts/onecol/panels-onecol.tpl.php
deleted file mode 100644
index 73ad5b8..0000000
--- a/plugins/layouts/onecol/panels-onecol.tpl.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-/**
- * @file
- * Template for a 3 column panel layout.
- *
- * This template provides a very simple "one column" panel display layout.
- *
- * Variables:
- * - $id: An optional CSS id to use for the layout.
- * - $content: An array of content, each item in the array is keyed to one
- *   panel of the layout. This layout supports the following sections:
- *   $content['middle']: The only panel in the layout.
- */
-?>
-<div class="panel-display panel-1col clearfix" <?php if (!empty($css_id)) { print "id=\"$css_id\""; } ?>>
-  <div class="panel-panel panel-col">
-    <div><?php print $content['middle']; ?></div>
-  </div>
-</div>
diff --git a/plugins/layouts/twocol/panels-twocol.html.twig b/plugins/layouts/twocol/panels-twocol.html.twig
new file mode 100644
index 0000000..d1796ef
--- /dev/null
+++ b/plugins/layouts/twocol/panels-twocol.html.twig
@@ -0,0 +1,25 @@
+{#
+/**
+ * @file
+ * Template for a 2 column panel layout.
+ *
+ * This template provides a two column panel display layout, with
+ * each column roughly equal in width.
+ *
+ * Variables:
+ * - $id: An optional CSS id to use for the layout.
+ * - $content: An array of content, each item in the array is keyed to one
+ *   panel of the layout. This layout supports the following sections:
+ *   - $content['left']: Content in the left column.
+ *   - $content['right']: Content in the right column.
+ */
+#}
+<div class="panel-display panel-2col clearfix" {% if css_id %}{{ css_id }}{% endif %}>
+  <div class="panel-panel panel-col-first">
+    <div class="inside">{{ content.left }}</div>
+  </div>
+
+  <div class="panel-panel panel-col-last">
+    <div class="inside">{{ content.right }}</div>
+  </div>
+</div>
diff --git a/plugins/layouts/twocol/panels-twocol.tpl.php b/plugins/layouts/twocol/panels-twocol.tpl.php
deleted file mode 100644
index 2cda08e..0000000
--- a/plugins/layouts/twocol/panels-twocol.tpl.php
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-/**
- * @file
- * Template for a 2 column panel layout.
- *
- * This template provides a two column panel display layout, with
- * each column roughly equal in width.
- *
- * Variables:
- * - $id: An optional CSS id to use for the layout.
- * - $content: An array of content, each item in the array is keyed to one
- *   panel of the layout. This layout supports the following sections:
- *   - $content['left']: Content in the left column.
- *   - $content['right']: Content in the right column.
- */
-?>
-<div class="panel-display panel-2col clearfix" <?php if (!empty($css_id)) { print "id=\"$css_id\""; } ?>>
-  <div class="panel-panel panel-col-first">
-    <div class="inside"><?php print $content['left']; ?></div>
-  </div>
-
-  <div class="panel-panel panel-col-last">
-    <div class="inside"><?php print $content['right']; ?></div>
-  </div>
-</div>
diff --git a/src/Plugin/DisplayVariant/PanelsDisplayVariant.php b/src/Plugin/DisplayVariant/PanelsDisplayVariant.php
index f877c90..54b4271 100644
--- a/src/Plugin/DisplayVariant/PanelsDisplayVariant.php
+++ b/src/Plugin/DisplayVariant/PanelsDisplayVariant.php
@@ -25,6 +25,8 @@ use Drupal\page_manager\Plugin\ConditionVariantTrait;
 use Drupal\page_manager\Plugin\ContextAwareVariantInterface;
 use Drupal\page_manager\Plugin\ContextAwareVariantTrait;
 use Drupal\page_manager\Plugin\PageAwareVariantInterface;
+use Drupal\layout_plugin\Layout;
+use Drupal\layout_plugin\Plugin\Layout\LayoutInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -42,6 +44,13 @@ class PanelsDisplayVariant extends VariantBase implements ContextAwareVariantInt
   use ConditionVariantTrait;
 
   /**
+   * The layout handler.
+   *
+   * @var \Drupal\layout_plugin\Plugin\Layout\LayoutInterface
+   */
+  protected $layout;
+
+  /**
    * The context handler.
    *
    * @var \Drupal\Core\Plugin\Context\ContextHandlerInterface
@@ -108,9 +117,33 @@ class PanelsDisplayVariant extends VariantBase implements ContextAwareVariantInt
   }
 
   /**
+   * Returns instance of the layout plugin used by this page variant.
+   *
+   * @return \Drupal\layout_plugin\Plugin\Layout\LayoutInterface
+   *   Layout plugin instance.
+   */
+  public function getLayout() {
+    if (!isset($this->layout)) {
+      $this->layout = Layout::layoutPluginManager()->createInstance($this->configuration['layout'], array());
+    }
+    return $this->layout;
+  }
+
+  /**
    * {@inheritdoc}
    */
-  public function build() {
+  public function getRegionNames() {
+    return $this->getLayout()->getRegionNames();
+  }
+
+  /**
+   * Build render arrays for each of the regions.
+   *
+   * @return
+   *   An associative array keyed by region id, containing the render array
+   *   representing the content of each region.
+   */
+  protected function buildRegions() {
     $build = array();
     $contexts = $this->getContexts();
     foreach ($this->getRegionAssignments() as $region => $blocks) {
@@ -151,11 +184,29 @@ class PanelsDisplayVariant extends VariantBase implements ContextAwareVariantInt
   /**
    * {@inheritdoc}
    */
+  public function build() {
+    $regions = $this->buildRegions();
+    if ($layout = $this->getLayout()) {
+      return $layout->build($regions);
+    }
+    return $regions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildConfigurationForm($form, $form_state);
 
     // Do not allow blocks to be added until the display variant has been saved.
     if (!$this->id()) {
+      $form['layout'] = array(
+        '#title' => $this->t('Layout'),
+        '#type' => 'select',
+        '#options' => Layout::getLayoutOptions(array('group_by_category' => TRUE)),
+        '#default_value' => NULL
+      );
+
       return $form;
     }
 
@@ -329,9 +380,13 @@ class PanelsDisplayVariant extends VariantBase implements ContextAwareVariantInt
   public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
     parent::submitConfigurationForm($form, $form_state);
 
+    if ($form_state->hasValue('layout')) {
+      $this->configuration['layout'] = $form_state->getValue('layout');
+    }
+
     // If the blocks were rearranged, update their values.
-    if (!empty($form_state['values']['blocks'])) {
-      foreach ($form_state['values']['blocks'] as $block_id => $block_values) {
+    if ($form_state->hasValue('blocks')) {
+      foreach ($form_state->getValue('blocks') as $block_id => $block_values) {
         $this->updateBlock($block_id, $block_values);
       }
     }
