diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 790949a..38fc856 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -229,6 +229,9 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb
       include_once DRUPAL_ROOT . '/' . $theme->owner;
     }
   }
+  // Load twig as secondary always available engine
+  // @todo Make twig the default engine and remove this
+  include_once DRUPAL_ROOT . '/core/themes/engines/twig/twig.engine';
 
   if (isset($registry_callback)) {
     _theme_registry_callback($registry_callback, array($theme, $base_theme, $theme_engine));
@@ -468,6 +471,28 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
         if (!isset($info['path'])) {
           $result[$hook]['template'] = $path . '/templates/' . $info['template'];
         }
+        if ($type == 'module') {
+          // Add two render engines for modules
+          // @todo Remove and make twig the default engine
+          $render_engines = array(
+            '.twig' => 'twig',
+            '.tpl.php' => 'phptemplate'
+          );
+
+          // Find the best engine for this template
+          foreach ($render_engines as $extension => $engine) {
+            // Render the output using the template file.
+            $template_file = $result[$hook]['template'] . $extension;
+            if (isset($info['path'])) {
+              $template_file = $info['path'] . '/' . $template_file;
+            }
+            if (file_exists($template_file)) {
+              $result[$hook]['template_file'] = $template_file;
+              $result[$hook]['engine'] = $engine;
+              break;
+            }
+          }
+        }
       }
 
       // Allow variable processors for all theming hooks, whether the hook is
@@ -1054,6 +1079,11 @@ function theme($hook, $variables = array()) {
           $extension = $extension_function();
         }
       }
+      elseif (isset($info['engine'])) {
+        if (function_exists($info['engine'] . '_render_template')) {
+          $render_function = $info['engine'] . '_render_template';
+        }
+      }
     }
 
     // In some cases, a template implementation may not have had
@@ -1077,6 +1107,12 @@ function theme($hook, $variables = array()) {
     if (isset($info['path'])) {
       $template_file = $info['path'] . '/' . $template_file;
     }
+
+    // Modules can override this
+    if (isset($info['template_file'])) {
+      $template_file = $info['template_file'];
+    }
+
     $output = $render_function($template_file, $variables);
   }
 
@@ -1252,7 +1288,13 @@ function drupal_find_theme_templates($cache, $extension, $path) {
       $matches = preg_grep('/^' . $pattern . '/', $patterns);
       if ($matches) {
         foreach ($matches as $match) {
-          $file = substr($match, 0, strpos($match, '.'));
+          $file = $match;
+          // Chop off the remaining extensions if there are any. $template already
+          // has the rightmost extension removed, but there might still be more,
+          // such as with .tpl.php, which still has .tpl in $template at this point.
+          if (($pos = strpos($match, '.')) !== FALSE) {
+            $file = substr($match, 0, $pos);
+          }
           // Put the underscores back in for the hook name and register this pattern.
           $arg_name = isset($info['variables']) ? 'variables' : 'render element';
           $implementations[strtr($file, '-', '_')] = array(
@@ -2910,6 +2952,7 @@ function drupal_common_theme() {
     ),
     'datetime' => array(
       'variables' => array('timestamp' => NULL, 'text' => NULL, 'attributes' => array(), 'html' => FALSE),
+      'template' => 'datetime',
     ),
     'status_messages' => array(
       'variables' => array('display' => NULL),
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index ed15dd5..f295a0f 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -55,11 +55,13 @@ public function build(ContainerBuilder $container) {
       ->setFactoryMethod('getConnection')
       ->addArgument('slave');
     $container->register('typed_data', 'Drupal\Core\TypedData\TypedDataManager');
-    // Add the user's storage for temporary, non-cache data.
     $container->register('lock', 'Drupal\Core\Lock\DatabaseLockBackend');
     $container->register('user.tempstore', 'Drupal\user\TempStoreFactory')
       ->addArgument(new Reference('database'))
       ->addArgument(new Reference('lock'));
+    $container->register('twig', 'Twig_Environment')
+      ->setFactoryClass('Drupal\Core\Template\TwigFactory')
+      ->setFactoryMethod('get');
 
     $container->register('router.dumper', '\Drupal\Core\Routing\MatcherDumper')
       ->addArgument(new Reference('database'));
diff --git a/core/lib/Drupal/Core/Template/TwigFactory.php b/core/lib/Drupal/Core/Template/TwigFactory.php
new file mode 100644
index 0000000..7df9914
--- /dev/null
+++ b/core/lib/Drupal/Core/Template/TwigFactory.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\Core\Template\TwigFactory.
+ *
+ * This is used for rendering templates with twig.
+ */
+
+namespace Drupal\Core\Template;
+use Twig_Environment;
+use Twig_Filter_Function;
+use Twig_Function_Function;
+use Twig_Loader_Filesystem;
+
+/**
+ * Initializes twig object
+ */
+class TwigFactory {
+  public static function get() {
+    // @TODO: Maybe we will have our own loader later.
+    $loader = new Twig_Loader_Filesystem(DRUPAL_ROOT);
+    $twig = new Twig_Environment($loader, array(
+        'cache' => DRUPAL_ROOT . '/compilation_cache',
+        // @TODO Maybe enable cache, once rebuild has been sorted.
+        'cache' => FALSE,
+        // @TODO: Remove in followup issue.
+        'autoescape' => FALSE,
+        // @TODO: Remove in followup issue to handle exceptions gracefully.
+        'strict_variables' => FALSE,
+    ));
+
+    // The node visitor is needed to wrap all variables with render -> twig_render() function.
+    $twig->addNodeVisitor(new TwigNodeVisitor);
+
+    $functions = array(
+      'hide' => 'twig_hide',
+      'render' => 'twig_render',
+      'show' => 'twig_show',
+      'unset' => 'unset'
+    );
+    $filters = array(
+      't' => 't'
+    );
+
+    foreach ($functions as $function => $php_function) {
+      $twig->addFunction($function, new Twig_Function_Function('Drupal\Core\Template\TwigReferenceFunctions::' . $php_function));
+    }
+
+    foreach ($filters as $filter => $php_function) {
+      $twig->addFilter($filter, new Twig_Filter_Function('Drupal\Core\Template\TwigReferenceFunctions::' . $php_function));
+    }
+
+    // @TODO remove URL once http://drupal.org/node/1778610 is resolved.
+    $twig->addFunction('url', new Twig_Function_Function('Drupal\Core\Template\TwigReferenceFunctions::' . 'url'));
+    return $twig;
+  }
+}
diff --git a/core/lib/Drupal/Core/Template/TwigNodeVisitor.php b/core/lib/Drupal/Core/Template/TwigNodeVisitor.php
new file mode 100644
index 0000000..64ee54d
--- /dev/null
+++ b/core/lib/Drupal/Core/Template/TwigNodeVisitor.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Template\TwigNodeVisitor.
+ */
+
+namespace Drupal\Core\Template;
+use Twig_NodeVisitorInterface;
+use Twig_NodeInterface;
+use Twig_Environment;
+use Twig_Node_Print;
+use Twig_Node;
+use Twig_Node_Expression_Function;
+
+class TwigNodeVisitor implements Twig_NodeVisitorInterface {
+
+  /**
+   * Called before child nodes are visited.
+   *
+   * @param Twig_NodeInterface $node The node to visit
+   * @param Twig_Environment   $env  The Twig environment instance
+   *
+   * @return Twig_NodeInterface The modified node
+   */
+  function enterNode(Twig_NodeInterface $node, Twig_Environment $env) {
+    return $node;
+  }
+
+  /**
+   * Called after child nodes are visited.
+   *
+   * We use this to inject a call to render -> twig_render() before
+   * anything is printed.
+   *
+   * @param Twig_NodeInterface $node The node to visit
+   * @param Twig_Environment   $env  The Twig environment instance
+   *
+   * @return Twig_NodeInterface The modified node
+   */
+  function leaveNode(Twig_NodeInterface $node, Twig_Environment $env) {
+    if ($node instanceof Twig_Node_Print) {
+      $class = get_class($node);
+      return new $class(
+        new Twig_Node_Expression_Function('render', new Twig_Node(array($node->getNode('expr'))), $node->getLine()),
+        $node->getLine()
+      );
+    }
+    return $node;
+  }
+
+  /**
+   * Returns the priority for this visitor.
+   *
+   * Priority should be between -10 and 10 (0 is the default).
+   *
+   * @return integer The priority level
+   */
+  function getPriority() {
+    return 0;
+  }
+}
diff --git a/core/lib/Drupal/Core/Template/TwigReference.php b/core/lib/Drupal/Core/Template/TwigReference.php
new file mode 100644
index 0000000..d35881e
--- /dev/null
+++ b/core/lib/Drupal/Core/Template/TwigReference.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Template\TwigReference.
+ */
+
+namespace Drupal\Core\Template;
+use ArrayObject;
+
+class TwigReference extends ArrayObject {
+
+  /** Internally hold reference to original array */
+  protected $writable_ref = array();
+
+  public function __construct(&$array = NULL) {
+    $this->writable_ref = &$array;
+    parent::__construct();
+  }
+
+  /**
+   * Sets a reference in the internal storage.
+   */
+  public function setReference(&$array) {
+    $this->exchangeArray($array);
+    $this->writable_ref = &$array;
+  }
+
+  /**
+  * Gets a reference to the internal storage.
+  */
+  public function &getReference() {
+    return $this->writable_ref;
+  }
+
+  /**
+   * Sets offset in internal reference and internal storage to value.
+   *
+   * This is just for completeness, but should never be used, because
+   * twig cannot set properties and should not.
+   *
+   * @link http://php.net/manual/en/arrayaccess.offsetset.php
+   * @param mixed $offset
+   *   The offset to assign the value to.
+   * @param mixed $value
+   *   The value to set.
+   */
+  public function offsetSet($offset, $value) {
+    $this->writable_ref[$offset] = $value;
+    parent::offsetSet($offset, $value);
+  }
+
+  /**
+   * Retrieves offset from internal reference.
+   *
+   * In case of a render array, it is wrapped
+   * again within a TwigReference object.
+   *
+   * @link http://php.net/manual/en/arrayaccess.offsetget.php
+   * @param mixed $offset
+   *   The offset to retrieve.
+   *
+   * @return mixed Can return all value types.
+   */
+  public function offsetGet($offset) {
+    if (!is_array($this->writable_ref[$offset]) || $offset[0] == '#') {
+      return $this->writable_ref[$offset];
+    }
+
+    // Wrap the returned array in a new TwigReference
+    $x = new TwigReference();
+    $x->setReference($this->writable_ref[$offset]);
+    return $x;
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Template/TwigReferenceFunctions.php b/core/lib/Drupal/Core/Template/TwigReferenceFunctions.php
new file mode 100644
index 0000000..52b235b
--- /dev/null
+++ b/core/lib/Drupal/Core/Template/TwigReferenceFunctions.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Template\TwigReferenceFunctions.
+ */
+
+namespace Drupal\Core\Template;
+
+class TwigReferenceFunctions {
+
+    /**
+     * Magic function to call functions called from twig templates by reference.
+     *
+     * This checks if the array provided by value is containing a reference to the
+     * original version. If yes it replaces the argument with its reference.
+     *
+     * @see TwigReference
+     * @see twig_convert_to_reference
+    */
+    public static function __callStatic($name, $arguments) {
+      foreach ($arguments as $key => $val) {
+        if (is_object($val) && $val instanceof TwigReference) {
+          $arguments[$key] = &$val->getReference();
+        }
+      }
+
+      // Needed to pass by reference -- could also restrict to maximum one argument instead
+      $args = array();
+      foreach ($arguments as $key => &$arg) {
+        $args[$key] = &$arg;
+      }
+
+      return call_user_func_array($name, $args);
+    }
+}
+
diff --git a/core/modules/node/templates/node.twig b/core/modules/node/templates/node.twig
new file mode 100644
index 0000000..8f1e21b
--- /dev/null
+++ b/core/modules/node/templates/node.twig
@@ -0,0 +1,110 @@
+{#
+/**
+ * @file
+ * Default theme implementation to display a node.
+ *
+ * Available variables:
+ * - label: the (sanitized) title of the node.
+ * - content: An array of node items. Use {{ content }} to print them all,
+ *   or print a subset such as {{ content.field_example }}. Use
+ *   {% hide(content.field_example) %} to temporarily suppress the printing
+ *   of a given element.
+ * - user_picture: The node author's picture from user-picture.twig.
+ * - date: Formatted creation date. Preprocess functions can reformat it by
+ *   calling format_date() with the desired parameters on the $created variable.
+ * - name: Themed username of node author output from theme_username().
+ * - node_url: Direct URL of the current node.
+ * - display_submitted: Whether submission information should be displayed.
+ * - submitted: Submission information created from $name and $date during
+ *   template_preprocess_node().
+ * - attributes: An instance of Attributes class that can be manipulated as an
+ *    array and printed as a string.
+ *    It includes the 'class' information, which includes:
+ *   - node: The current template type; for example, "theming hook".
+ *   - node-[type]: The current node type. For example, if the node is a
+ *     "Article" it would result in "node-article". Note that the machine
+ *     name will often be in a short form of the human readable label.
+ *   - view-mode-[view_mode]: The View Mode of the node; for example, "teaser"
+ *     or "full".
+ *   - preview: Nodes in preview mode.
+ *   The following are controlled through the node publishing options.
+ *   - promoted: Nodes promoted to the front page.
+ *   - sticky: Nodes ordered above other non-sticky nodes in teaser
+ *     listings.
+ *   - unpublished: Unpublished nodes visible only to administrators.
+ * - title_prefix: Additional output populated by modules, intended to be
+ *   displayed in front of the main title tag that appears in the template.
+ * - title_suffix: Additional output populated by modules, intended to be
+ *   displayed after the main title tag that appears in the template.
+ *
+ * Other variables:
+ * - node: Full node entity. Contains data that may not be safe.
+ * - type: Node type; for example, page, article, etc.
+ * - comment_count: Number of comments attached to the node.
+ * - uid: User ID of the node author.
+ * - created: Time the node was published formatted in Unix timestamp.
+ * - zebra: Outputs either "even" or "odd". Useful for zebra striping in
+ *   teaser listings.
+ * - id: Position of the node. Increments each time it's output.
+ *
+ * Node status variables:
+ * - view_mode: View mode; for example, "teaser" or "full".
+ * - teaser: Flag for the teaser state (shortcut for $view_mode == 'teaser').
+ * - page: Flag for the full page state.
+ * - promote: Flag for front page promotion state.
+ * - sticky: Flags for sticky post setting.
+ * - status: Flag for published status.
+ * - comment: State of comment settings for the node.
+ * - readmore: Flags true if the teaser content of the node cannot hold the
+ *   main body content.
+ * - is_front: Flags true when presented in the front page.
+ * - logged_in: Flags true when the current user is a logged-in member.
+ * - is_admin: Flags true when the current user is an administrator.
+ *
+ * Field variables: for each field instance attached to the node a corresponding
+ * variable is defined; for example, $node->body becomes body. When needing to
+ * access a field's raw values, developers/themers are strongly encouraged to
+ * use these variables. Otherwise they will have to explicitly specify the
+ * desired field language; for example, $node->body['en'], thus overriding any
+ * language negotiation rule that was previously applied.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_node()
+ *
+ * @ingroup themeable
+ */
+#}
+{#
+  @todo: might be a good idea to remove the id attribute, because if that gets
+  rendered twice on a page this is invalid CSS
+  for example: two lists in different view modes.
+#}
+<!-- node.twig - proudly powered by twig engine -->
+<article id="node-{{ node.nid }}" class="{{ attributes.class }} clearfix" {{- attributes }}>
+
+  {{ title_prefix }}
+  {% if page != true %}
+    <h2 {{- title_attributes }}>
+      <a href="{{ node_url }}" rel="bookmark">{{ label }}</a>
+    </h2>
+  {% endif %}
+  {{ title_suffix }}
+
+  {% if display_submitted %}
+    <footer>
+      {{ user_picture }}
+      <p class="submitted">{{ submitted }}</p>
+    </footer>
+  {% endif %}
+
+  <div class="content" {{- content_attributes }}>
+    {# We hide the comments and links now so that we can render them later. #}
+    {{ hide(content.comments) }}
+    {{ hide(content.links) }}
+    {{ content }}
+  </div>
+
+  {{ content.links }}
+  {{ content.comments }}
+
+</article>
diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php
index 484d00b..a21cfbe 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php
@@ -187,4 +187,19 @@ function testRegistryRebuild() {
   function testClassLoading() {
     new ThemeClass();
   }
+
+  /**
+   * Tests drupal_find_theme_templates
+   */
+  function testFindThemeTemplates() {
+    $cache = array();
+
+    // Prime the theme cache
+    foreach (module_implements('theme') as $module) {
+      _theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module));
+    }
+
+    $templates = drupal_find_theme_templates($cache, '.tpl.php', drupal_get_path('theme', 'test_theme'));
+    $this->assertEqual($templates['node__1']['template'], 'node--1', 'Template node--1.tpl.php was found in test_theme.');
+  }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTestTwig.php b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTestTwig.php
new file mode 100644
index 0000000..6a9d988
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTestTwig.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\Theme\ThemeTest.
+ */
+
+namespace Drupal\system\Tests\Theme;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests low-level theme functions.
+ */
+class ThemeTestTwig extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('theme_test');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Twig Engine',
+      'description' => 'Test theme functions with twig.',
+      'group' => 'Theme',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+    theme_enable(array('test_theme_twig'));
+  }
+
+  /**
+   * Ensures a themes template is overrideable based on the 'template' filename.
+   */
+  function testTemplateOverride() {
+    variable_set('theme_default', 'test_theme_twig');
+    $this->drupalGet('theme-test/template-test');
+    $this->assertText('Success: Template overridden.', t('Template overridden by defined \'template\' filename.'));
+  }
+
+  /**
+   * Tests drupal_find_theme_templates
+   */
+  function testFindThemeTemplates() {
+
+    $cache = array();
+
+    // Prime the theme cache
+    foreach (module_implements('theme') as $module) {
+      _theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module));
+    }
+
+    // Check for correct content
+    // @todo Remove this tests once double engine code is removed
+
+    $this->assertEqual($cache['node']['template_file'], 'core/modules/node/templates/node.twig', 'Node is using node.twig as template file');
+    $this->assertEqual($cache['node']['engine'], 'twig', 'Node is using twig engine');
+
+    $this->assertEqual($cache['theme_test_template_test']['template_file'], 'core/modules/system/tests/modules/theme_test/templates/theme_test.template_test.tpl.php', 'theme_test is using theme_test.template_test.tpl.php as template file');
+    $this->assertEqual($cache['theme_test_template_test']['engine'], 'phptemplate', 'theme_test is using phptemplate as engine.');
+
+    $templates = drupal_find_theme_templates($cache, '.twig', drupal_get_path('theme', 'test_theme_twig'));
+    $this->assertEqual($templates['node__1']['template'], 'node--1', 'Template node--1.twig was found in test_theme_twig.');
+  }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/TwigReferenceUnitTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/TwigReferenceUnitTest.php
new file mode 100644
index 0000000..dd4c718
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Theme/TwigReferenceUnitTest.php
@@ -0,0 +1,144 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\Theme\TwigReferenceUnitTest.
+ */
+
+namespace Drupal\system\Tests\Theme;
+
+use Drupal\simpletest\UnitTestBase;
+use Drupal\Core\Template\TwigReference;
+use Drupal\Core\Template\TwigReferenceFunctions;
+
+class TwigReferenceObjectTest {
+  public function __construct($nid, $title) {
+    $this->nid = $nid;
+    $this->title = $title;
+  }
+}
+
+/**
+ * Unit tests for TwigReference class.
+ */
+class TwigReferenceUnitTest extends UnitTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Theme Twig References',
+      'description' => 'Tests TwigReference functions',
+      'group' => 'Theme',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+    $this->variables = array(
+      'foo' => 'bar',
+      'baz' => array(
+        'foo' => '42',
+        'bar' => '23',
+      ),
+      'node' => new TwigReferenceObjectTest(
+        42,
+        'test node'
+      )
+    );
+  }
+
+  /**
+   * Test function for TwigReference class
+   */
+  function testTwigReference() {
+    // Create a new TwigReference wrapper
+    $wrapper = new TwigReference();
+    $wrapper->setReference($this->variables);
+
+    // Check that strings are returned as strings
+    $foo = $wrapper['foo'];
+    $this->assertEqual($foo, $this->variables['foo'], 'String returned from TwigReference is the same');
+    $this->assertTrue(is_string($foo), 'String returned from TwigReference is of type string');
+
+    // Check that arrays are wrapped again as TwigReference objects
+    $baz = $wrapper['baz'];
+    $this->assertTrue(is_object($baz), 'Array returned from TwigReference is of type object');
+    $this->assertTrue($baz instanceof TwigReference, 'Array returned from TwigReference is instance of TwigReference');
+
+    // Check that getReference is giving back a reference to the original array
+
+    $ref = &$baz->getReference();
+    $this->assertTrue(is_array($ref), 'getReference returns an array');
+
+    // Now modify $ref
+    $ref['#hidden'] = TRUE;
+    $this->assertEqual($ref['#hidden'], $this->variables['baz']['#hidden'], 'Property set on reference is passed to original array.');
+    $this->assertEqual($ref['#hidden'], $baz['#hidden'], 'Property set on reference is passed to wrapper.');
+
+    // Now modify $baz
+    $baz['hi'] = 'hello';
+
+    $this->assertEqual($baz['hi'], $this->variables['baz']['hi'], 'Property set on TwigReference object is passed to original array.');
+    $this->assertEqual($baz['hi'], $ref['hi'], 'Property set on TwigReference object is passed to reference.');
+
+    // Check that an object is passed through directly
+    $node = $wrapper['node'];
+    $this->assertTrue(is_object($node), 'Object returned from TwigReference is of type object');
+    $this->assertTrue($node instanceof TwigReferenceObjectTest, 'Object returned from TwigReference is instance of TwigReferenceObjectTest');
+  }
+
+  /**
+   * Test function for TwigReferenceFunctions class
+   */
+  function testTwigReferenceFunctions() {
+
+    // Create wrapper
+    $content = &$this->variables;
+
+    // Use twig nomenclature
+    $context['content'] = $content;
+
+    // Twig converts {{ hide(content.baz) }} to the following code
+
+    // This will have failed, because getAttribute returns a value and not a reference
+
+    try {
+      if (isset($context["content"])) {
+        $_content_ = $context["content"];
+      }
+      else {
+        $_content_ = NULL;
+      }
+      TwigReferenceFunctions::hide($this->getAttribute($_content_, "baz"));
+    }
+    catch (Exception $e) {
+      // Catch the critical warning that a value was passed by reference
+    }
+    $this->assertFalse(isset($content['baz']['#printed']), 'baz is not hidden in content after hide() via value');
+
+    // Now lets do the same with some TwigReference magic!
+
+    $content_wrapper = new TwigReference();
+    $content_wrapper->setReference($content);
+    $context['content'] = $content_wrapper;
+
+    // Twig converts {{ hide(content.baz) }} to the following code
+
+    // This will succeed, because getAttribute returns a value, but it is an object
+
+    if (isset($context["content"])) {
+      $_content_ = $context["content"];
+    }
+    else {
+      $_content_ = NULL;
+    }
+    TwigReferenceFunctions::hide($this->getAttribute($_content_, "baz"));
+
+    $this->assertTrue(isset($content['baz']['#printed']), 'baz is hidden in content after hide() via TwigReference object');
+
+    $type = TwigReferenceFunctions::gettype($this->getAttribute($_content_, "baz"));
+    $this->assertEqual($type, 'array', 'Type returned via TwigReferenceFunctions:: is an array.');
+
+    $type = gettype($this->getAttribute($_content_, "baz"));
+    $this->assertEqual($type, 'object', 'Type returned without TwigReferenceFunctions:: is an object.');
+  }
+
+  /**
+   *  Helper function to somehow simulate Twigs getAttribute function
+   */
+  public function getAttribute($array, $offset) {
+    if (isset($array[$offset])) {
+      return $array[$offset];
+    }
+
+    return NULL;
+  }
+}
diff --git a/core/modules/system/templates/datetime.twig b/core/modules/system/templates/datetime.twig
new file mode 100644
index 0000000..a74aeac
--- /dev/null
+++ b/core/modules/system/templates/datetime.twig
@@ -0,0 +1,31 @@
+{#
+/**
+ * Returns HTML for a date / time.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - timestamp: (optional) A UNIX timestamp for the datetime attribute. If the
+ *     datetime cannot be represented as a UNIX timestamp, use a valid datetime
+ *     attribute value in $variables['attributes']['datetime'].
+ *   - text: (optional) The content to display within the <time> element. Set
+ *     'html' to TRUE if this value is already sanitized for output in HTML.
+ *     Defaults to a human-readable representation of the timestamp value or the
+ *     datetime attribute value using format_date().
+ *     When invoked as #theme or #theme_wrappers of a render element, the
+ *     rendered #children are autoamtically taken over as 'text', unless #text
+ *     is explicitly set.
+ *   - attributes: (optional) An associative array of HTML attributes to apply
+ *     to the <time> element. A datetime attribute in 'attributes' overrides the
+ *     'timestamp'. To create a valid datetime attribute value from a UNIX
+ *     timestamp, use format_date() with one of the predefined 'html_*' formats.
+ *   - html: (optional) Whether 'text' is HTML markup (TRUE) or plain-text
+ *     (FALSE). Defaults to FALSE. For example, to use a SPAN tag within the
+ *     TIME element, this must be set to TRUE, or the SPAN tag will be escaped.
+ *     It is the responsibility of the caller to properly sanitize the value
+ *     contained in 'text' (or within the SPAN tag in aforementioned example).
+ *
+ * @see template_preprocess_datetime()
+ * @see http://www.w3.org/TR/html5-author/the-time-element.html#attr-time-datetime
+ */
+#}
+<time class="{{ attributes.class }}" {{ attributes }}>{{ html?text:(text|e) }}</time>
diff --git a/core/modules/system/tests/modules/theme_test/theme_test.template_test.tpl.php b/core/modules/system/tests/modules/theme_test/templates/theme_test.template_test.tpl.php
similarity index 100%
rename from core/modules/system/tests/modules/theme_test/theme_test.template_test.tpl.php
rename to core/modules/system/tests/modules/theme_test/templates/theme_test.template_test.tpl.php
diff --git a/core/modules/system/tests/modules/theme_test/theme_test.module b/core/modules/system/tests/modules/theme_test/theme_test.module
index a05bc46..f231b49 100644
--- a/core/modules/system/tests/modules/theme_test/theme_test.module
+++ b/core/modules/system/tests/modules/theme_test/theme_test.module
@@ -27,6 +27,7 @@ function theme_test_system_theme_info() {
   $themes['test_theme'] = drupal_get_path('module', 'system') . '/tests/themes/test_theme/test_theme.info';
   $themes['test_basetheme'] = drupal_get_path('module', 'system') . '/tests/themes/test_basetheme/test_basetheme.info';
   $themes['test_subtheme'] = drupal_get_path('module', 'system') . '/tests/themes/test_subtheme/test_subtheme.info';
+  $themes['test_theme_twig'] = drupal_get_path('module', 'system') . '/tests/themes/test_theme_twig/test_theme_twig.info';
   return $themes;
 }
 
diff --git a/core/modules/system/tests/themes/test_theme/node--1.tpl.php b/core/modules/system/tests/themes/test_theme/node--1.tpl.php
new file mode 100644
index 0000000..81974ce
--- /dev/null
+++ b/core/modules/system/tests/themes/test_theme/node--1.tpl.php
@@ -0,0 +1,4 @@
+<?php
+  // node--1.tpl.php - Dummy file for finding the template
+?>
+Node Content Dummy
diff --git a/core/modules/system/tests/themes/test_theme_twig/node--1.twig b/core/modules/system/tests/themes/test_theme_twig/node--1.twig
new file mode 100644
index 0000000..79148f1
--- /dev/null
+++ b/core/modules/system/tests/themes/test_theme_twig/node--1.twig
@@ -0,0 +1,4 @@
+{#
+  // node--1.twig - Dummy file for finding the template
+#}
+Node Content Dummy
diff --git a/core/modules/system/tests/themes/test_theme_twig/template.php b/core/modules/system/tests/themes/test_theme_twig/template.php
new file mode 100644
index 0000000..8275818
--- /dev/null
+++ b/core/modules/system/tests/themes/test_theme_twig/template.php
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * Tests a theme overriding a suggestion of a base theme hook.
+ */
+function test_theme_theme_test__suggestion($variables) {
+  return 'Theme hook implementor=test_theme_theme_test__suggestion(). Foo=' . $variables['foo'];
+}
+
+/**
+ * Tests a theme implementing an alter hook.
+ *
+ * The confusing function name here is due to this being an implementation of
+ * the alter hook invoked when the 'theme_test' module calls
+ * drupal_alter('theme_test_alter').
+ */
+function test_theme_theme_test_alter_alter(&$data) {
+  $data = 'test_theme_theme_test_alter_alter was invoked';
+}
diff --git a/core/modules/system/tests/themes/test_theme_twig/test_theme_twig.info b/core/modules/system/tests/themes/test_theme_twig/test_theme_twig.info
new file mode 100644
index 0000000..5097adb
--- /dev/null
+++ b/core/modules/system/tests/themes/test_theme_twig/test_theme_twig.info
@@ -0,0 +1,5 @@
+name = Test theme for Twig
+description = Theme for testing the theme system with twig engine
+engine = twig
+core = 8.x
+hidden = TRUE
diff --git a/core/modules/system/tests/themes/test_theme_twig/theme_test.template_test.twig b/core/modules/system/tests/themes/test_theme_twig/theme_test.template_test.twig
new file mode 100644
index 0000000..6cda319
--- /dev/null
+++ b/core/modules/system/tests/themes/test_theme_twig/theme_test.template_test.twig
@@ -0,0 +1,2 @@
+{# Output for Theme API test #}
+Success: Template overridden.
diff --git a/core/themes/engines/twig/twig.engine b/core/themes/engines/twig/twig.engine
new file mode 100644
index 0000000..e534205
--- /dev/null
+++ b/core/themes/engines/twig/twig.engine
@@ -0,0 +1,127 @@
+<?php
+
+/**
+ * @file
+ * Handles integration of Twig templates with the Drupal theme system.
+ */
+use Drupal\Core\Template\TwigNodeVisitor;
+use Drupal\Core\Template\TwigReferenceFunctions;
+use Drupal\Core\Template\TwigReference;
+
+/**
+ * Implements hook_theme().
+ */
+function twig_theme($existing, $type, $theme, $path) {
+  return drupal_find_theme_templates($existing, '.twig', $path);
+}
+
+/**
+ * Implements hook_extension().
+ */
+function twig_extension() {
+  return '.twig';
+}
+
+/**
+ * Implements hook_init().
+ */
+function twig_init($template) {
+  $file = dirname($template->filename) . '/template.php';
+  if (file_exists($file)) {
+    include_once DRUPAL_ROOT . '/' . $file;
+  }
+}
+
+/**
+ * Convert into a TwigReference object.
+ *
+ * This is needed to workaround a limitation
+ * of twig to only provide variables by value.
+ *
+ * By saving a reference to the original array
+ * the variable can be passed by reference.
+ *
+ * Only complex variables that are no attributes
+ * are converted.
+ *
+ * @see TwigReference
+ * @see TwigReferenceFunctions
+ *
+*/
+function twig_convert_to_reference(&$elements, &$original) {
+  $needs_selfreference = FALSE;
+
+  foreach ($elements as $key => $val) {
+    if (!is_array($val) || $key[0] == '#') {
+      continue;
+    }
+    if (!is_numeric($key)) {
+      $needs_selfreference = TRUE;
+    }
+  }
+  if ($needs_selfreference) {
+    $elements = new TwigReference();
+    $elements->setReference($original);
+  }
+}
+
+/**
+ * Render twig templates.
+ *
+ * All complex variables that are no attributes are converted
+ * into TwigReference ArrayObjects that allow passing of arrays
+ * by reference within twig.
+ *
+ * @see twig_convert_to_reference
+ */
+function twig_render_template($template_file, $variables) {
+  $original = $variables;
+  foreach ($variables as $key => $val) {
+    if (!is_array($val) || $key[0] == '#') {
+      continue;
+    }
+    twig_convert_to_reference($variables[$key], $original[$key]);
+  }
+
+  return drupal_container()->get('twig')->loadTemplate($template_file)->render($variables);
+}
+
+/**
+ * Wrapper around render for twig content.
+ *
+ * @param arg String, Object or Render Array
+ */
+function twig_render($arg) {
+  // Keep Twig_Markup objects intact to prepare for later autoescaping support
+  if ($arg instanceOf Twig_Markup) {
+    return $arg;
+  }
+
+  if (is_scalar($arg)) {
+    return $arg;
+  }
+
+  if (is_object($arg)) {
+    if (method_exists($arg, '__toString')) {
+      return (string) $arg;
+    }
+    throw new Exception(t('Object of type "@class" cannot be printed.', array('@class' => get_class($arg))));
+  }
+
+  // This is a normal render array.
+  return render($arg);
+}
+
+/**
+ * Wrapper around hide() that does not return the content.
+ */
+function twig_hide(&$element) {
+  hide($element);
+}
+
+/**
+ * Wrapper around show() that does not return the content.
+ */
+function twig_show(&$element) {
+  show($element);
+}
