diff --git a/core/lib/Drupal/Core/Render/Element/Markup.php b/core/lib/Drupal/Core/Render/Element/Markup.php
index ffa87ed..f586328 100644
--- a/core/lib/Drupal/Core/Render/Element/Markup.php
+++ b/core/lib/Drupal/Core/Render/Element/Markup.php
@@ -125,21 +125,60 @@ public static function ensureMarkupIsSafe(array $elements) {
       return $elements;
     }
 
+    $replacement = [];
+    $search = [];
+
+    if (!is_array($elements['#markup'])) {
+      $markups[] = $elements['#markup'];
+      $is_markup_array = FALSE;
+    }
+    else {
+      $markups = $elements['#markup'];
+      $is_markup_array = TRUE;
+    }
+
     $strategy = isset($elements['#safe_strategy']) ? $elements['#safe_strategy'] : static::SAFE_STRATEGY_FILTER;
-    if (SafeMarkup::isSafe($elements['#markup'])) {
-      // Nothing to do as #markup is already marked as safe.
-      return $elements;
+    foreach($markups as $key => $markup) {
+      if (SafeMarkup::isSafe($markup)) {
+        if (!$is_markup_array) {
+          // If there is only one element and it is safe we can just return.
+          return $elements;
+        }
+        // Create a placeholder so we can replace the safe string after escaping
+        // or filtering.
+        $placeholder = '!!!safemarkup #' . $key . '!!!';
+        $search[] = $placeholder;
+        $replacement[] = $markup;
+        $markups[$key] = $placeholder;
+      }
+    }
+
+    // Ensure the separator is safe.
+    $separator = '';
+    if (isset($elements['#separator'])) {
+      if (SafeMarkup::isSafe($elements['#separator'])) {
+        $separator = '!!!safemarkup separator!!!';
+        $search[] = $elements['#separator'];
+        $replacement[] = $elements['#separator'];
+      }
+      else {
+        $separator = HtmlUtility::escape($elements['#separator']);
+      }
     }
-    elseif ($strategy == static::SAFE_STRATEGY_ESCAPE) {
-      $markup = HtmlUtility::escape($elements['#markup']);
+
+    // Create the string and make it safe.
+    $string = implode($separator, $markups);
+    if ($strategy == static::SAFE_STRATEGY_ESCAPE) {
+      $string = HtmlUtility::escape($string);
     }
     else {
       // The default behaviour is to XSS filter using the admin tag list.
       $tags = isset($elements['#allowed_tags']) ? $elements['#allowed_tags'] : Xss::getAdminTagList();
-      $markup = Xss::filter($elements['#markup'], $tags);
+      $string = Xss::filter($string, $tags);
     }
 
-    $elements['#markup'] = SafeString::create($markup);
+    // Do the safe replacements and create a safe string.
+    $elements['#markup'] = SafeString::create(str_replace($search, $replacement, $string));
 
     return $elements;
   }
diff --git a/core/tests/Drupal/Tests/Core/Render/RendererTest.php b/core/tests/Drupal/Tests/Core/Render/RendererTest.php
index c7d2ad4..9ff0546 100644
--- a/core/tests/Drupal/Tests/Core/Render/RendererTest.php
+++ b/core/tests/Drupal/Tests/Core/Render/RendererTest.php
@@ -60,7 +60,7 @@ public function testRenderBasic($build, $expected, callable $setup_code = NULL)
       $setup_code();
     }
 
-    if (isset($build['#markup'])) {
+    if (isset($build['#markup']) && !is_array($build['#markup'])) {
       $this->assertFalse(SafeMarkup::isSafe($build['#markup']), 'The #markup value is not marked safe before rendering.');
     }
     $render_output = $this->renderer->renderRoot($build);
@@ -141,6 +141,42 @@ public function providerTestRenderBasic() {
       '#children' => 'foo',
       'child' => ['#markup' => 'bar'],
     ], 'foo'];
+    // #markup array based renderable array.
+    $data[] = [[
+      '#markup' => ['foo', 'bar'],
+    ], 'foobar'];
+    // #markup array based renderable array that will be escaped.
+    $data[] = [[
+      '#markup' => ['<em>foo</em>', '<em>bar</em>'],
+      '#safe_strategy' => Markup::SAFE_STRATEGY_ESCAPE
+    ], '&lt;em&gt;foo&lt;/em&gt;&lt;em&gt;bar&lt;/em&gt;'];
+    // #markup array based renderable array where one element will be escaped.
+    $data[] = [[
+      '#markup' => [SafeString::create('<em>foo</em>'), '<em>bar</em>'],
+      '#safe_strategy' => Markup::SAFE_STRATEGY_ESCAPE
+    ], '<em>foo</em>&lt;em&gt;bar&lt;/em&gt;'];
+    // #markup array based renderable array where elements will be filter using
+    // the admin filter.
+    $data[] = [[
+      '#markup' => ['<em>foo</em>', '<em><script>alert();</script>bar</em>'],
+    ], '<em>foo</em><em>alert();bar</em>'];
+    // #markup array based renderable array where elements will be filter using
+    // the admin filter.
+    $data[] = [[
+      '#markup' => ['<em>foo</em>', '<em><strong>bar</strong></em>'],
+      '#allowed_tags' => ['strong']
+    ], 'foo<strong>bar</strong>'];
+    // #markup array based renderable array using a separator.
+    $data[] = [[
+      '#markup' => ['one', 'two', 'three'],
+      '#separator' => ', '
+    ], 'one, two, three'];
+    // #markup array based renderable array using a separator that is escaped.
+    $data[] = [[
+      '#markup' => ['one', 'two', 'three'],
+      '#separator' => '</p><p>'
+    ], 'one&lt;/p&gt;&lt;p&gt;two&lt;/p&gt;&lt;p&gt;three'];
+
 
     // Part 2: render arrays using #theme and #theme_wrappers.
 
