diff --git a/core/includes/common.inc b/core/includes/common.inc
index a4805c0..ebfd58a 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -3728,7 +3728,33 @@ function drupal_render_page($page) {
  *   - If this element has an array of #theme_wrappers defined and
  *     #render_children is not set, #children is then re-rendered by passing the
  *     element in its current state to theme() successively for each item in
- *     #theme_wrappers.
+ *     #theme_wrappers. Since #theme and #theme_wrappers hooks often define
+ *     variables with the same names it is possible to explicitly override each
+ *     attribute passed to each #theme_wrappers hook by setting the hook name as
+ *     the key and an array of overrides as the value in #theme_wrappers array.
+ *     For example, if we have a render element as follows:
+ *     @code
+ *     array(
+ *       '#theme' => 'image',
+ *       '#attributes' => array('class' => 'foo'),
+ *       '#theme_wrappers' => array('container'),
+*      );
+*      @endcode
+*
+*      and we need to pass the class 'bar' as an attribute for 'container', we
+*      can rewrite our element thus:
+*      @code
+*      array(
+*        '#theme' => 'image',
+*        '#attributes' => array('class' => 'foo'),
+*        '#theme_wrappers' => array(
+*          'container' => array(
+*            '#attributes' => array('class' => 'bar'),
+*          ),
+*        ),
+*      );
+*      @endcode
+*
  *   - If this element has an array of #post_render functions defined, they are
  *     called sequentially to modify the rendered #children. Unlike #pre_render
  *     functions, #post_render functions are passed both the rendered #children
@@ -3857,8 +3883,24 @@ function drupal_render(&$elements) {
   // If the internal #render_children property is set, do not call the
   // #theme_wrappers function(s) to prevent infinite recursion.
   if (isset($elements['#theme_wrappers']) && !isset($elements['#render_children'])) {
-    foreach ($elements['#theme_wrappers'] as $theme_wrapper) {
-      $elements['#children'] = theme($theme_wrapper, $elements);
+    foreach ($elements['#theme_wrappers'] as $key => $value) {
+      // If the value of a #theme_wrappers item is an array then the theme hook
+      // is found in the key of the item and the value contains attribute
+      // overrides. Attribute overrides replace key/value pairs in $elements for
+      // only this theme() call. This allows #theme hooks and #theme_wrappers
+      // hooks to share variable names without conflict or ambiguity.
+      $wrapper_elements = $elements;
+      if (is_array($value)) {
+        $wrapper_hook = $key;
+        foreach ($value as $attribute => $override) {
+          $wrapper_elements[$attribute] = $override;
+        }
+      }
+      else {
+        $wrapper_hook = $value;
+      }
+
+      $elements['#children'] = theme($wrapper_hook, $wrapper_elements);
     }
   }
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php
index ec115e3..c964577 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php
@@ -73,6 +73,68 @@ function testDrupalRenderBasics() {
         'expected' => '',
       ),
 
+      // Test that #theme and #theme_wrappers can co-exist on an element.
+      array(
+        'name' => '#theme and #theme_wrappers basic',
+        'value' => array(
+          '#theme' => 'common_test_foo',
+          '#foo' => 'foo',
+          '#bar' => 'bar',
+          '#theme_wrappers' => array('container'),
+          '#attributes' => array('class' => 'baz'),
+        ),
+        'expected' => '<div class="baz">foobar</div>',
+      ),
+      // Test that #theme_wrappers can disambiguate element attributes shared
+      // with rendering methods that build #children by using the alternate
+      // #theme_wrappers attribute override syntax.
+      array(
+        'name' => '#theme and #theme_wrappers attribute disambiguation',
+        'value' => array(
+          '#type' => 'link',
+          '#theme_wrappers' => array(
+            'container' => array(
+              '#attributes' => array('class' => 'baz'),
+            ),
+          ),
+          '#attributes' => array('id' => 'foo'),
+          '#href' => 'http://drupal.org',
+          '#title' => 'bar',
+        ),
+        'expected' => '<div class="baz"><a href="http://drupal.org" id="foo">bar</a></div>',
+      ),
+      // Test that #theme_wrappers can disambiguate element attributes when the
+      // "base" attribute is not set for #theme.
+      array(
+        'name' => '#theme_wrappers attribute disambiguation with undefined #theme attribute',
+        'value' => array(
+          '#type' => 'link',
+          '#href' => 'http://drupal.org',
+          '#title' => 'foo',
+          '#theme_wrappers' => array(
+            'container' => array(
+              '#attributes' => array('class' => 'baz'),
+            ),
+          ),
+        ),
+        'expected' => '<div class="baz"><a href="http://drupal.org">foo</a></div>',
+      ),
+      // Two 'container' #theme_wrappers, one using the "base" attributes and
+      // one using an override.
+      array(
+        'name' => 'Two #theme_wrappers container hooks with different attributes',
+        'value' => array(
+          '#attributes' => array('class' => 'foo'),
+          '#theme_wrappers' => array(
+            'container' => array(
+              '#attributes' => array('class' => 'bar'),
+            ),
+            'container',
+          ),
+        ),
+        'expected' => '<div class="foo"><div class="bar"></div></div>',
+      ),
+
       // Test handling of #markup as a fallback for #theme hooks.
       // Simple #markup with no theme.
       array(
