diff --git a/core/core.services.yml b/core/core.services.yml
index 872e2ff..0717e16 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -185,6 +185,9 @@ services:
     arguments: ['@csrf_token', '@config.factory']
     tags:
       - { name: theme_negotiator, priority: 1000 }
+  plugin.manager.theme_engine:
+    class: Drupal\Core\Theme\ThemeEngineManager
+    parent: default_plugin_manager
   container.namespaces:
     class: ArrayObject
     arguments: [ '%container.namespaces%' ]
@@ -715,7 +718,7 @@ services:
     class: Zend\Feed\Writer\Extension\WellFormedWeb\Renderer\Entry
   theme.registry:
     class: Drupal\Core\Theme\Registry
-    arguments: ['@cache.cache', '@lock', '@module_handler']
+    arguments: ['@cache.cache', '@lock', '@module_handler', '@plugin.manager.theme_engine']
     tags:
       - { name: needs_destruction }
   authentication:
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index f98df80..b706ca0 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -247,13 +247,12 @@ function _drupal_theme_initialize($theme, $base_theme = array()) {
     // Include the engine.
     include_once DRUPAL_ROOT . '/' . $theme->owner;
 
-    $theme_engine = $theme->engine;
-    if (function_exists($theme_engine . '_init')) {
-      foreach ($base_theme as $base) {
-        call_user_func($theme_engine . '_init', $base);
-      }
-      call_user_func($theme_engine . '_init', $theme);
+    /** @var \Drupal\Core\Theme\ThemeEngineInterface $theme_engine */
+    $theme_engine = \Drupal::service('plugin.manager.theme_engine')->createInstance($theme->engine);
+    foreach ($base_theme as $base) {
+      $theme_engine->initTheme($base);
     }
+    $theme_engine->initTheme($theme);
   }
   else {
     // include non-engine theme files
@@ -563,22 +562,9 @@ function _theme($hook, $variables = array()) {
     }
   }
   else {
-    $render_function = 'twig_render_template';
-    $extension = '.html.twig';
-
     // The theme engine may use a different extension and a different renderer.
+    /** @var \Drupal\Core\Theme\ThemeEngineInterface $theme_engine */
     global $theme_engine;
-    if (isset($theme_engine)) {
-      if ($info['type'] != 'module') {
-        if (function_exists($theme_engine . '_render_template')) {
-          $render_function = $theme_engine . '_render_template';
-        }
-        $extension_function = $theme_engine . '_extension';
-        if (function_exists($extension_function)) {
-          $extension = $extension_function();
-        }
-      }
-    }
 
     // In some cases, a template implementation may not have had
     // template_preprocess() run (for example, if the default implementation is
@@ -611,7 +597,7 @@ function _theme($hook, $variables = array()) {
     }
 
     // Render the output using the template file.
-    $template_file = $info['template'] . $extension;
+    $template_file = $info['template'] . $theme_engine->getExtension();
     if (isset($info['path'])) {
       $template_file = $info['path'] . '/' . $template_file;
     }
@@ -625,7 +611,7 @@ function _theme($hook, $variables = array()) {
     if (isset($theme_hook_suggestion)) {
       $variables['theme_hook_suggestion'] = $theme_hook_suggestion;
     }
-    $output = $render_function($template_file, $variables);
+    $output = $theme_engine->renderTemplate($template_file, $variables);
   }
 
   // restore path_to_theme()
diff --git a/core/lib/Drupal/Core/Annotation/ThemeEngine.php b/core/lib/Drupal/Core/Annotation/ThemeEngine.php
new file mode 100644
index 0000000..45913f9
--- /dev/null
+++ b/core/lib/Drupal/Core/Annotation/ThemeEngine.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Annotation\ThemeEngine.
+ */
+
+namespace Drupal\Core\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines a theme engine annotation.
+ *
+ * @Annotation
+ */
+class ThemeEngine extends Plugin {
+
+  /**
+   * The plugin ID.
+   *
+   * @var string
+   */
+  public $id;
+
+}
diff --git a/core/lib/Drupal/Core/Theme/Plugin/ThemeEngine/Twig.php b/core/lib/Drupal/Core/Theme/Plugin/ThemeEngine/Twig.php
new file mode 100644
index 0000000..1709866
--- /dev/null
+++ b/core/lib/Drupal/Core/Theme/Plugin/ThemeEngine/Twig.php
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Theme\Plugin\ThemeEngine\Twig.
+ */
+
+namespace Drupal\Core\Theme\Plugin\ThemeEngine;
+
+use Drupal\Component\Utility\Settings;
+use Drupal\Core\Extension\Extension;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Plugin\PluginBase;
+use Drupal\Core\Template\TwigEnvironment;
+use Drupal\Core\Theme\ThemeEngineInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Handles integration of Twig templates with the Drupal theme system.
+ *
+ * @ThemeEngine(
+ *   id = "twig"
+ * )
+ */
+class Twig extends PluginBase implements ThemeEngineInterface, ContainerFactoryPluginInterface {
+
+  public function __construct(array $configuration, $plugin_id, array $plugin_definition, TwigEnvironment $twig_enviroment, Settings $settings) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->twigEnviroment = $twig_enviroment;
+    $this->settings = $settings;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('twig'),
+      $container->get('settings')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function initTheme(Extension $theme) {
+    $theme->load();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function theme($existing, $type, $theme, $path) {
+    $templates = drupal_find_theme_functions($existing, array($theme));
+    $templates += drupal_find_theme_templates($existing, '.html.twig', $path);
+    return $templates;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getExtension() {
+    return '.html.twig';
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * If the Twig debug setting is enabled, HTML comments including _theme() call
+   * and template file name suggestions will surround the template markup.
+   */
+  public function renderTemplate($template_file, $variables) {
+    $variables['_references'] = array();
+    $output = array(
+      'debug_prefix'    => '',
+      'debug_info'      => '',
+      'rendered_markup' => $this->twigEnviroment->loadTemplate($template_file)->render($variables),
+      'debug_suffix'    => '',
+    );
+    if ($this->settings->get('twig_debug', FALSE)) {
+      $output['debug_prefix'] .= "\n\n<!-- THEME DEBUG -->";
+      $output['debug_prefix'] .= "\n<!-- CALL: _theme('{$variables['theme_hook_original']}') -->";
+      if (!empty($variables['theme_hook_suggestions'])) {
+        $extension = $this->getExtension();
+        $current_template = basename($template_file);
+        $suggestions = $variables['theme_hook_suggestions'];
+        $suggestions[] = $variables['theme_hook_original'];
+        foreach ($suggestions as &$suggestion) {
+          $template = strtr($suggestion, '_', '-') . $extension;
+          $prefix = ($template == $current_template) ? 'x' : '*';
+          $suggestion = $prefix . ' ' . $template;
+        }
+        $output['debug_info'] .= "\n<!-- FILE NAME SUGGESTIONS:\n   " . implode("\n   ", $suggestions) . "\n-->";
+      }
+      $output['debug_info']   .= "\n<!-- BEGIN OUTPUT from '{$template_file}' -->\n";
+      $output['debug_suffix'] .= "\n<!-- END OUTPUT from '{$template_file}' -->\n\n";
+    }
+    return implode('', $output);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preprocess() {
+    // TODO: Implement preprocess() method.
+  }
+
+
+}
diff --git a/core/lib/Drupal/Core/Theme/Registry.php b/core/lib/Drupal/Core/Theme/Registry.php
index e84b33b..5f9d821 100644
--- a/core/lib/Drupal/Core/Theme/Registry.php
+++ b/core/lib/Drupal/Core/Theme/Registry.php
@@ -36,9 +36,9 @@ class Registry implements DestructableInterface {
   protected $baseThemes;
 
   /**
-   * The name of the theme engine of $theme.
+   * The theme engine instance.
    *
-   * @var string
+   * @var \Drupal\Core\Theme\ThemeEngineInterface
    */
   protected $engine;
 
@@ -123,13 +123,16 @@ class Registry implements DestructableInterface {
    *   The lock backend.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler to use to load modules.
+   * @param \Drupal\Core\Theme\ThemeEngineManager $theme_engine_manager
+   *   The theme engine manager.
    * @param string $theme_name
    *   (optional) The name of the theme for which to construct the registry.
    */
-  public function __construct(CacheBackendInterface $cache, LockBackendInterface $lock, ModuleHandlerInterface $module_handler, $theme_name = NULL) {
+  public function __construct(CacheBackendInterface $cache, LockBackendInterface $lock, ModuleHandlerInterface $module_handler, ThemeEngineManager $theme_engine_manager, $theme_name = NULL) {
     $this->cache = $cache;
     $this->lock = $lock;
     $this->moduleHandler = $module_handler;
+    $this->themeEngineManager = $theme_engine_manager;
     $this->init($theme_name);
   }
 
@@ -183,14 +186,12 @@ protected function init($theme_name = NULL) {
 
       // @see _drupal_theme_initialize()
       if (isset($this->theme->engine)) {
-        $this->engine = $this->theme->engine;
+        $this->engine = $this->themeEngineManager->createInstance($this->theme->engine);
         include_once DRUPAL_ROOT . '/' . $this->theme->owner;
-        if (function_exists($this->theme->engine . '_init')) {
-          foreach ($this->baseThemes as $base) {
-            call_user_func($this->theme->engine . '_init', $base);
-          }
-          call_user_func($this->theme->engine . '_init', $this->theme);
+        foreach ($this->baseThemes as $base) {
+          $this->engine->initTheme($base);
         }
+        $this->engine->initTheme($this->theme);
       }
     }
   }
@@ -409,8 +410,13 @@ protected function processExtension(&$cache, $name, $type, $theme, $path) {
 
     // Invoke the hook_theme() implementation, preprocess what is returned, and
     // merge it into $cache.
-    $function = $name . '_theme';
-    if (function_exists($function)) {
+    if ($type == 'theme_engine') {
+      $function = array($this->engine, 'theme');
+    }
+    else {
+      $function = $name . '_theme';
+    }
+    if (is_callable($function)) {
       $result = $function($cache, $type, $theme, $path);
       foreach ($result as $hook => $info) {
         // When a theme or engine overrides a module's theme function
@@ -474,7 +480,7 @@ protected function processExtension(&$cache, $name, $type, $theme, $path) {
           elseif ($type == 'theme_engine' || $type == 'base_theme_engine') {
             // Theme engines get an extra set that come before the normally
             // named variable preprocessors.
-            $prefixes[] = $name . '_engine';
+            $prefixes[] = $name->getPluginId() . '_engine';
             // The theme engine registers on behalf of the theme using the
             // theme's name.
             $prefixes[] = $theme;
diff --git a/core/lib/Drupal/Core/Theme/ThemeEngineInterface.php b/core/lib/Drupal/Core/Theme/ThemeEngineInterface.php
new file mode 100644
index 0000000..825c60c
--- /dev/null
+++ b/core/lib/Drupal/Core/Theme/ThemeEngineInterface.php
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Theme\ThemeEngineInterface.
+ */
+
+namespace Drupal\Core\Theme;
+use Drupal\Core\Extension\Extension;
+
+/**
+ * Defines an interface for a theme engine.
+ *
+ * A theme engine controls how to render a render a template.
+ */
+interface ThemeEngineInterface {
+
+  /**
+   * Initializes a theme.
+   *
+   * The theme engine might load for example a .theme file to "load" a theme.
+   */
+  public function initTheme(Extension $theme);
+
+  /**
+   * Wraps hook_theme() for engines.
+   */
+  public function theme($existing, $type, $theme, $path);
+
+  /**
+   * Returns the extension used by the theme engine.
+   *
+   * @return string
+   *   The extension.
+   */
+  public function getExtension();
+
+  /**
+   * Renders a template.
+   *
+   * @param string $template_file
+   *   The file name of the template to render.
+   * @param array $variables
+   *   A keyed array of variables that will appear in the output.
+   *
+   * @retur string
+   *   The output generated by the template, plus any debug information.
+   */
+  public function renderTemplate($template_file, $variables);
+
+  /**
+   * Wraps a preprocess function for engines.
+   */
+  public function preprocess();
+
+}
diff --git a/core/lib/Drupal/Core/Theme/ThemeEngineManager.php b/core/lib/Drupal/Core/Theme/ThemeEngineManager.php
new file mode 100644
index 0000000..92b5c24
--- /dev/null
+++ b/core/lib/Drupal/Core/Theme/ThemeEngineManager.php
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Theme\ThemeEngineManager.
+ */
+
+namespace Drupal\Core\Theme;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Plugin\DefaultPluginManager;
+
+/**
+ * Defines a plugin manager for available theme engines.
+ */
+class ThemeEngineManager extends DefaultPluginManager {
+
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Plugin/ThemeEngine', $namespaces, $module_handler, 'Drupal\Core\Annotation\ThemeEngine');
+    $this->alterInfo('theme_engine');
+    $this->setCacheBackend($cache_backend, $language_manager, 'theme_engine_plugins');
+  }
+
+}
diff --git a/core/themes/engines/twig/twig.engine b/core/themes/engines/twig/twig.engine
index 74de2b8..7b532d0 100644
--- a/core/themes/engines/twig/twig.engine
+++ b/core/themes/engines/twig/twig.engine
@@ -5,97 +5,6 @@
  * Handles integration of Twig templates with the Drupal theme system.
  */
 
-use Drupal\Core\Extension\Extension;
-use Drupal\Component\Utility\Settings;
-
-/**
- * Implements hook_theme().
- */
-function twig_theme($existing, $type, $theme, $path) {
-  $templates = drupal_find_theme_functions($existing, array($theme));
-  $templates += drupal_find_theme_templates($existing, '.html.twig', $path);
-  return $templates;
-}
-
-/**
- * Implements hook_extension().
- */
-function twig_extension() {
-  return '.html.twig';
-}
-
-/**
- * Implements hook_init().
- */
-function twig_init(Extension $theme) {
-  $theme->load();
-}
-
-/**
- * Renders a Twig template.
- *
- * If the Twig debug setting is enabled, HTML comments including _theme() call
- * and template file name suggestions will surround the template markup.
- *
- * @param $template_file
- *   The file name of the template to render.
- * @param $variables
- *   A keyed array of variables that will appear in the output.
- *
- * @return
- *   The output generated by the template, plus any debug information.
- */
-function twig_render_template($template_file, $variables) {
-  $output = array(
-    'debug_prefix'    => '',
-    'debug_info'      => '',
-    'rendered_markup' => \Drupal::service('twig')->loadTemplate($template_file)->render($variables),
-    'debug_suffix'    => '',
-  );
-  if (Settings::get('twig_debug', FALSE)) {
-    $output['debug_prefix'] .= "\n\n<!-- THEME DEBUG -->";
-    $output['debug_prefix'] .= "\n<!-- CALL: _theme('{$variables['theme_hook_original']}') -->";
-    // If there are theme suggestions, reverse the array so more specific
-    // suggestions are shown first.
-    if (!empty($variables['theme_hook_suggestions'])) {
-      $variables['theme_hook_suggestions'] = array_reverse($variables['theme_hook_suggestions']);
-    }
-    // Add debug output for directly called suggestions like
-    // '#theme' => 'comment__node__article'.
-    if (strpos($variables['theme_hook_original'], '__') !== FALSE) {
-      $derived_suggestions[] = $hook = $variables['theme_hook_original'];
-      while ($pos = strrpos($hook, '__')) {
-        $hook = substr($hook, 0, $pos);
-        $derived_suggestions[] = $hook;
-      }
-      // Get the value of the base hook (last derived suggestion) and append it
-      // to the end of all theme suggestions.
-      $base_hook = array_pop($derived_suggestions);
-      $variables['theme_hook_suggestions'] = array_merge($derived_suggestions, $variables['theme_hook_suggestions']);
-      $variables['theme_hook_suggestions'][] = $base_hook;
-    }
-    if (!empty($variables['theme_hook_suggestions'])) {
-      $extension = twig_extension();
-      $current_template = basename($template_file);
-      $suggestions = $variables['theme_hook_suggestions'];
-      // Only add the original theme hook if it wasn't a directly called
-      // suggestion.
-      if (strpos($variables['theme_hook_original'], '__') === FALSE) {
-        $suggestions[] = $variables['theme_hook_original'];
-      }
-      foreach ($suggestions as &$suggestion) {
-        $template = strtr($suggestion, '_', '-') . $extension;
-        $prefix = ($template == $current_template) ? 'x' : '*';
-        $suggestion = $prefix . ' ' . $template;
-      }
-      $output['debug_info'] .= "\n<!-- FILE NAME SUGGESTIONS:\n   " . implode("\n   ", $suggestions) . "\n-->";
-    }
-    $output['debug_info']   .= "\n<!-- BEGIN OUTPUT from '{$template_file}' -->\n";
-    $output['debug_suffix'] .= "\n<!-- END OUTPUT from '{$template_file}' -->\n\n";
-  }
-  return implode('', $output);
-}
-
 /**
  * Wrapper around render() for twig printed output.
  *
