diff --git a/core/modules/filter/tests/src/Unit/FilterUninstallValidatorTest.php b/core/modules/filter/tests/src/Unit/FilterUninstallValidatorTest.php
index cb37bf4..4a4f7ba 100644
--- a/core/modules/filter/tests/src/Unit/FilterUninstallValidatorTest.php
+++ b/core/modules/filter/tests/src/Unit/FilterUninstallValidatorTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\Tests\filter\Unit;
 
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -160,10 +159,7 @@ public function testValidateNoMatchingFormats() {
       ]);
 
     $expected = [
-      SafeMarkup::format('Provides a filter plugin that is in use in the following filter formats: %formats', ['%formats' => implode(', ', [
-        'Filter Format 1 Label',
-        'Filter Format 2 Label',
-      ])]),
+      'Provides a filter plugin that is in use in the following filter formats: <em class="placeholder">Filter Format 1 Label, Filter Format 2 Label</em>'
     ];
     $reasons = $this->filterUninstallValidator->validate($this->randomMachineName());
     $this->assertSame($expected, $reasons);
diff --git a/core/modules/forum/tests/src/Unit/ForumUninstallValidatorTest.php b/core/modules/forum/tests/src/Unit/ForumUninstallValidatorTest.php
index 85145c2..560a872 100644
--- a/core/modules/forum/tests/src/Unit/ForumUninstallValidatorTest.php
+++ b/core/modules/forum/tests/src/Unit/ForumUninstallValidatorTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\Tests\forum\Unit;
 
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -127,10 +126,7 @@ public function testValidateHasTermsForVocabularyWithNodesAccess() {
     $module = 'forum';
     $expected = [
       'To uninstall Forum, first delete all <em>Forum</em> content',
-      SafeMarkup::format('To uninstall Forum, first delete all <a href="@url">%vocabulary</a> terms', [
-        '@url' => '/path/to/vocabulary/overview',
-        '%vocabulary' => 'Vocabulary label',
-      ]),
+      'To uninstall Forum, first delete all <a href="/path/to/vocabulary/overview"><em class="placeholder">Vocabulary label</em></a> terms',
     ];
     $reasons = $this->forumUninstallValidator->validate($module);
     $this->assertSame($expected, $reasons);
@@ -164,9 +160,7 @@ public function testValidateHasTermsForVocabularyWithNodesNoAccess() {
     $module = 'forum';
     $expected = [
       'To uninstall Forum, first delete all <em>Forum</em> content',
-      SafeMarkup::format('To uninstall Forum, first delete all %vocabulary terms', [
-        '%vocabulary' => 'Vocabulary label',
-      ]),
+      'To uninstall Forum, first delete all <em class="placeholder">Vocabulary label</em> terms',
     ];
     $reasons = $this->forumUninstallValidator->validate($module);
     $this->assertSame($expected, $reasons);
@@ -200,10 +194,7 @@ public function testValidateHasTermsForVocabularyAccess() {
 
     $module = 'forum';
     $expected = [
-      SafeMarkup::format('To uninstall Forum, first delete all <a href="@url">%vocabulary</a> terms', [
-        '@url' => '/path/to/vocabulary/overview',
-        '%vocabulary' => 'Vocabulary label',
-      ]),
+      'To uninstall Forum, first delete all <a href="/path/to/vocabulary/overview"><em class="placeholder">Vocabulary label</em></a> terms',
     ];
     $reasons = $this->forumUninstallValidator->validate($module);
     $this->assertSame($expected, $reasons);
@@ -236,9 +227,7 @@ public function testValidateHasTermsForVocabularyNoAccess() {
 
     $module = 'forum';
     $expected = [
-      SafeMarkup::format('To uninstall Forum, first delete all %vocabulary terms', [
-        '%vocabulary' => 'Vocabulary label',
-      ]),
+      'To uninstall Forum, first delete all <em class="placeholder">Vocabulary label</em> terms',
     ];
     $reasons = $this->forumUninstallValidator->validate($module);
     $this->assertSame($expected, $reasons);
diff --git a/core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php b/core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php
index 34f7590..345051b 100644
--- a/core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php
+++ b/core/modules/user/tests/src/Unit/UserAccessControlHandlerTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\Tests\user\Unit;
 
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Access\AccessResult;
 use Drupal\Tests\UnitTestCase;
 use Drupal\user\UserAccessControlHandler;
@@ -125,13 +124,8 @@ public function assertFieldAccess($field, $viewer, $target, $view, $edit) {
       ->will($this->returnValue($this->{$target}));
 
     foreach (array('view' => $view, 'edit' => $edit) as $operation => $result) {
-      $message = SafeMarkup::format("User @field field access returns @result with operation '@op' for @account accessing @target", array(
-        '@field' => $field,
-        '@result' => !isset($result) ? 'null' : ($result ? 'true' : 'false'),
-        '@op' => $operation,
-        '@account' => $viewer,
-        '@target' => $target,
-      ));
+      $result_text = !isset($result) ? 'null' : ($result ? 'true' : 'false');
+      $message = "User '$field' field access returns '$result_text' with operation '$operation' for '$viewer' accessing '$target'";
       $this->assertSame($result, $this->accessControlHandler->fieldAccess($operation, $field_definition, $this->{$viewer}, $this->items), $message);
     }
   }
diff --git a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php
index 3dedb82..b8db4fe 100644
--- a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php
+++ b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php
@@ -930,13 +930,10 @@ public function setKey($key, $value) {
 
 }
 
-
 namespace {
-  use Drupal\Component\Utility\SafeMarkup;
-
   if (!function_exists('t')) {
     function t($string, array $args = []) {
-      return SafeMarkup::format($string, $args);
+      return strtr($string, $args);
     }
   }
 }
diff --git a/core/modules/views/tests/src/Unit/Plugin/field/CounterTest.php b/core/modules/views/tests/src/Unit/Plugin/field/CounterTest.php
index 5a68eb2..5280370 100644
--- a/core/modules/views/tests/src/Unit/Plugin/field/CounterTest.php
+++ b/core/modules/views/tests/src/Unit/Plugin/field/CounterTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\Tests\views\Unit\Plugin\field;
 
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Tests\UnitTestCase;
 use Drupal\views\Entity\View;
 use Drupal\views\Plugin\views\field\Counter;
@@ -125,15 +124,9 @@ public function testSimpleCounter($i) {
     $expected = $i + 1;
 
     $counter = $counter_handler->getValue($this->testData[$i]);
-    $this->assertEquals($expected, $counter, SafeMarkup::format('The expected number (@expected) patches with the rendered number (@counter) failed', array(
-      '@expected' => $expected,
-      '@counter' => $counter
-    )));
+    $this->assertEquals($expected, $counter, 'The expected number matches with the counter number');
     $counter = $this->renderCounter($counter_handler, $this->testData[$i]);
-    $this->assertEquals($expected, $counter, SafeMarkup::format('The expected number (@expected) patches with the rendered number (@counter) failed', array(
-      '@expected' => $expected,
-      '@counter' => $counter
-    )));
+    $this->assertEquals($expected, $counter, 'The expected number matches with the rendered number');
   }
 
   /**
@@ -157,15 +150,9 @@ public function testCounterRandomStart($i) {
     $expected = $rand_start + $i;
 
     $counter = $counter_handler->getValue($this->testData[$i]);
-    $this->assertEquals($expected, $counter, SafeMarkup::format('The expected number (@expected) patches with the rendered number (@counter) failed', array(
-      '@expected' => $expected,
-      '@counter' => $counter
-    )));
+    $this->assertEquals($expected, $counter, 'The expected number matches with the counter number');
     $counter = $this->renderCounter($counter_handler, $this->testData[$i]);
-    $this->assertEquals($expected, $counter, SafeMarkup::format('The expected number (@expected) patches with the rendered number (@counter) failed', array(
-      '@expected' => $expected,
-      '@counter' => $counter
-    )));
+    $this->assertEquals($expected, $counter, 'The expected number matches with the rendered number');
   }
 
   /**
@@ -192,15 +179,9 @@ public function testCounterRandomPagerOffset($i) {
     $expected = $offset + $rand_start + $i;
 
     $counter = $counter_handler->getValue($this->testData[$i]);
-    $this->assertEquals($expected, $counter, SafeMarkup::format('The expected number (@expected) patches with the rendered number (@counter) failed', array(
-      '@expected' => $expected,
-      '@counter' => $counter
-    )));
+    $this->assertEquals($expected, $counter, 'The expected number matches with the counter number');
     $counter = $this->renderCounter($counter_handler, $this->testData[$i]);
-    $this->assertEquals($expected, $counter, SafeMarkup::format('The expected number (@expected) patches with the rendered number (@counter) failed', array(
-      '@expected' => $expected,
-      '@counter' => $counter
-    )));
+    $this->assertEquals($expected, $counter, 'The expected number matches with the rendered number');
   }
 
   /**
@@ -231,15 +212,9 @@ public function testCounterSecondPage($i) {
     $expected = $items_per_page + $offset + $rand_start + $i;
 
     $counter = $counter_handler->getValue($this->testData[$i]);
-    $this->assertEquals($expected, $counter, SafeMarkup::format('The expected number (@expected) patches with the rendered number (@counter) failed', array(
-      '@expected' => $expected,
-      '@counter' => $counter
-    )));
+    $this->assertEquals($expected, $counter, 'The expected number matches with the counter number');
     $counter = $this->renderCounter($counter_handler, $this->testData[$i]);
-    $this->assertEquals($expected, $counter, SafeMarkup::format('The expected number (@expected) patches with the rendered number (@counter) failed', array(
-      '@expected' => $expected,
-      '@counter' => $counter
-    )));
+    $this->assertEquals($expected, $counter, 'The expected number matches with the rendered number');
   }
 
   /**
diff --git a/core/modules/views/tests/src/Unit/ViewsDataHelperTest.php b/core/modules/views/tests/src/Unit/ViewsDataHelperTest.php
index 35713d7..a005678 100644
--- a/core/modules/views/tests/src/Unit/ViewsDataHelperTest.php
+++ b/core/modules/views/tests/src/Unit/ViewsDataHelperTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\Tests\views\Unit;
 
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Tests\UnitTestCase;
 use Drupal\views\ViewsDataHelper;
 use Drupal\views\Tests\ViewTestData;
@@ -106,7 +105,7 @@ public function testFetchFields() {
       array_walk($expected_keys, function(&$item) {
         $item = "views_test_data.$item";
       });
-      $this->assertEquals($expected_keys, array_keys($fields), SafeMarkup::format('Handlers of type @handler_type are not listed as expected.', array('@handler_type' => $handler_type)));
+      $this->assertEquals($expected_keys, array_keys($fields), "Handlers of type $handler_type are not listed as expected");
     }
 
     // Check for subtype filtering, so header and footer.
@@ -117,7 +116,7 @@ public function testFetchFields() {
       array_walk($expected_keys, function(&$item) {
         $item = "views_test_data.$item";
       });
-      $this->assertEquals($expected_keys, array_keys($fields), SafeMarkup::format('Sub_type @sub_type is not filtered as expected.', array('@sub_type' => $sub_type)));
+      $this->assertEquals($expected_keys, array_keys($fields), "Sub_type $sub_type is not filtered as expected.");
     }
   }
 
diff --git a/core/phpunit.xml.dist b/core/phpunit.xml.dist
index 743bf08..8b9e491 100644
--- a/core/phpunit.xml.dist
+++ b/core/phpunit.xml.dist
@@ -34,7 +34,9 @@
     </testsuite>
   </testsuites>
   <listeners>
-    <listener class="\Drupal\Tests\Standards\DrupalStandardsListener">
+    <listener class="\Drupal\Tests\Listeners\DrupalStandardsListener">
+    </listener>
+    <listener class="\Drupal\Tests\Listeners\SafeMarkupSideEffects">
     </listener>
   </listeners>
   <!-- Filter for coverage reports. -->
diff --git a/core/tests/Drupal/Tests/Component/Utility/RandomTest.php b/core/tests/Drupal/Tests/Component/Utility/RandomTest.php
index ead6469..a993100 100644
--- a/core/tests/Drupal/Tests/Component/Utility/RandomTest.php
+++ b/core/tests/Drupal/Tests/Component/Utility/RandomTest.php
@@ -8,7 +8,6 @@
 namespace Drupal\Tests\Component\Utility;
 
 use Drupal\Component\Utility\Random;
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -39,7 +38,7 @@ public function testRandomStringUniqueness() {
     $random = new Random();
     for ($i = 0; $i <= 50; $i++) {
       $str = $random->string(1, TRUE);
-      $this->assertFalse(isset($strings[$str]), SafeMarkup::format('Generated duplicate random string !string', array('!string' => $str)));
+      $this->assertFalse(isset($strings[$str]), 'Generated duplicate random string ' . $str);
       $strings[$str] = TRUE;
     }
   }
@@ -54,7 +53,7 @@ public function testRandomNamesUniqueness() {
     $random = new Random();
     for ($i = 0; $i <= 10; $i++) {
       $str = $random->name(1, TRUE);
-      $this->assertFalse(isset($names[$str]), SafeMarkup::format('Generated duplicate random name !name', array('!name' => $str)));
+      $this->assertFalse(isset($names[$str]), 'Generated duplicate random name ' . $str);
       $names[$str] = TRUE;
     }
   }
diff --git a/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php
index 90a475f..bfa4cb3 100644
--- a/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php
+++ b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php
@@ -8,6 +8,7 @@
 namespace Drupal\Tests\Component\Utility;
 
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Component\Utility\SafeStringInterface;
 use Drupal\Component\Utility\Xss;
 use Drupal\Tests\UnitTestCase;
 
@@ -183,11 +184,11 @@ function testFormat($string, $args, $expected, $message, $expected_is_safe) {
   function providerFormat() {
     $tests[] = array('Simple text', array(), 'Simple text', 'SafeMarkup::format leaves simple text alone.', TRUE);
     $tests[] = array('Escaped text: @value', array('@value' => '<script>'), 'Escaped text: &lt;script&gt;', 'SafeMarkup::format replaces and escapes string.', TRUE);
-    $tests[] = array('Escaped text: @value', array('@value' => SafeMarkup::set('<span>Safe HTML</span>')), 'Escaped text: <span>Safe HTML</span>', 'SafeMarkup::format does not escape an already safe string.', TRUE);
+    $tests[] = array('Escaped text: @value', array('@value' => SafeMarkupTestSafeString::create('<span>Safe HTML</span>')), 'Escaped text: <span>Safe HTML</span>', 'SafeMarkup::format does not escape an already safe string.', TRUE);
     $tests[] = array('Placeholder text: %value', array('%value' => '<script>'), 'Placeholder text: <em class="placeholder">&lt;script&gt;</em>', 'SafeMarkup::format replaces, escapes and themes string.', TRUE);
-    $tests[] = array('Placeholder text: %value', array('%value' => SafeMarkup::set('<span>Safe HTML</span>')), 'Placeholder text: <em class="placeholder"><span>Safe HTML</span></em>', 'SafeMarkup::format does not escape an already safe string themed as a placeholder.', TRUE);
+    $tests[] = array('Placeholder text: %value', array('%value' => SafeMarkupTestSafeString::create('<span>Safe HTML</span>')), 'Placeholder text: <em class="placeholder"><span>Safe HTML</span></em>', 'SafeMarkup::format does not escape an already safe string themed as a placeholder.', TRUE);
     $tests[] = array('Verbatim text: !value', array('!value' => '<script>'), 'Verbatim text: <script>', 'SafeMarkup::format replaces verbatim string as-is.', FALSE);
-    $tests[] = array('Verbatim text: !value', array('!value' => SafeMarkup::set('<span>Safe HTML</span>')), 'Verbatim text: <span>Safe HTML</span>', 'SafeMarkup::format replaces verbatim string as-is.', TRUE);
+    $tests[] = array('Verbatim text: !value', array('!value' => SafeMarkupTestSafeString::create('<span>Safe HTML</span>')), 'Verbatim text: <span>Safe HTML</span>', 'SafeMarkup::format replaces verbatim string as-is.', TRUE);
 
     return $tests;
   }
@@ -259,7 +260,7 @@ public function providerReplace() {
     // Subject unsafe.
     $tests[] = [
       '<placeholder>',
-      SafeMarkup::set('foo'),
+      SafeMarkupTestSafeString::create('foo'),
       '<placeholder>bazqux',
       'foobazqux',
       FALSE,
@@ -268,8 +269,8 @@ public function providerReplace() {
     // All safe.
     $tests[] = [
       '<placeholder>',
-      SafeMarkup::set('foo'),
-      SafeMarkup::set('<placeholder>barbaz'),
+      SafeMarkupTestSafeString::create('foo'),
+      SafeMarkupTestSafeString::create('<placeholder>barbaz'),
       'foobarbaz',
       TRUE,
     ];
@@ -279,7 +280,7 @@ public function providerReplace() {
     $tests[] = [
       '<placeholder>',
       'fubar',
-      SafeMarkup::set('<placeholder>barbaz'),
+      SafeMarkupTestSafeString::create('<placeholder>barbaz'),
       'fubarbarbaz',
       FALSE,
     ];
@@ -287,8 +288,8 @@ public function providerReplace() {
     // Array with all safe.
     $tests[] = [
       ['<placeholder1>', '<placeholder2>', '<placeholder3>'],
-      [SafeMarkup::set('foo'), SafeMarkup::set('bar'), SafeMarkup::set('baz')],
-      SafeMarkup::set('<placeholder1><placeholder2><placeholder3>'),
+      [SafeMarkupTestSafeString::create('foo'), SafeMarkupTestSafeString::create('bar'), SafeMarkupTestSafeString::create('baz')],
+      SafeMarkupTestSafeString::create('<placeholder1><placeholder2><placeholder3>'),
       'foobarbaz',
       TRUE,
     ];
@@ -296,8 +297,8 @@ public function providerReplace() {
     // Array with unsafe replacement.
     $tests[] = [
       ['<placeholder1>', '<placeholder2>', '<placeholder3>',],
-      [SafeMarkup::set('bar'), SafeMarkup::set('baz'), 'qux'],
-      SafeMarkup::set('<placeholder1><placeholder2><placeholder3>'),
+      [SafeMarkupTestSafeString::create('bar'), SafeMarkupTestSafeString::create('baz'), 'qux'],
+      SafeMarkupTestSafeString::create('<placeholder1><placeholder2><placeholder3>'),
       'barbazqux',
       FALSE,
     ];
@@ -320,3 +321,27 @@ public function __toString() {
   }
 
 }
+
+/**
+ * Marks text as safe.
+ *
+ * SafeMarkupTestSafeString is used to mark text as safe because
+ * SafeMarkup::set() is a global static that affects all tests.
+ */
+class SafeMarkupTestSafeString implements SafeStringInterface {
+
+  protected $string;
+
+  public function __construct($string) {
+    $this->string = $string;
+  }
+
+  public function __toString() {
+    return $this->string;
+  }
+
+  public static function create($string) {
+    $safe_string = new static($string);
+    return $safe_string;
+  }
+}
diff --git a/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php b/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php
index 2c258d6..6823dc1 100644
--- a/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php
+++ b/core/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php
@@ -8,7 +8,6 @@
 namespace Drupal\Tests\Component\Utility;
 
 use Drupal\Component\Utility\UrlHelper;
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -94,7 +93,7 @@ public function providerTestValidAbsoluteData() {
   public function testValidAbsolute($url, $scheme) {
     $test_url = $scheme . '://' . $url;
     $valid_url = UrlHelper::isValid($test_url, TRUE);
-    $this->assertTrue($valid_url, SafeMarkup::format('@url is a valid URL.', array('@url' => $test_url)));
+    $this->assertTrue($valid_url, $test_url . ' is a valid URL.');
   }
 
   /**
@@ -125,7 +124,7 @@ public function providerTestInvalidAbsolute() {
   public function testInvalidAbsolute($url, $scheme) {
     $test_url = $scheme . '://' . $url;
     $valid_url = UrlHelper::isValid($test_url, TRUE);
-    $this->assertFalse($valid_url, SafeMarkup::format('@url is NOT a valid URL.', array('@url' => $test_url)));
+    $this->assertFalse($valid_url, $test_url . ' is NOT a valid URL.');
   }
 
   /**
@@ -159,7 +158,7 @@ public function providerTestValidRelativeData() {
   public function testValidRelative($url, $prefix) {
     $test_url = $prefix . $url;
     $valid_url = UrlHelper::isValid($test_url);
-    $this->assertTrue($valid_url, SafeMarkup::format('@url is a valid URL.', array('@url' => $test_url)));
+    $this->assertTrue($valid_url, $test_url . ' is a valid URL.');
   }
 
   /**
@@ -190,7 +189,7 @@ public function providerTestInvalidRelativeData() {
   public function testInvalidRelative($url, $prefix) {
     $test_url = $prefix . $url;
     $valid_url = UrlHelper::isValid($test_url);
-    $this->assertFalse($valid_url, SafeMarkup::format('@url is NOT a valid URL.', array('@url' => $test_url)));
+    $this->assertFalse($valid_url, $test_url . ' is NOT a valid URL.');
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/Controller/TitleResolverTest.php b/core/tests/Drupal/Tests/Core/Controller/TitleResolverTest.php
index 5189531..1d8c416 100644
--- a/core/tests/Drupal/Tests/Core/Controller/TitleResolverTest.php
+++ b/core/tests/Drupal/Tests/Core/Controller/TitleResolverTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\Tests\Core\Controller;
 
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Controller\TitleResolver;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\HttpFoundation\ParameterBag;
@@ -151,7 +150,7 @@ class TitleCallback {
    *   Returns the example string.
    */
   public function example($value) {
-    return SafeMarkup::format('test @value', array('@value' => $value));
+    return 'test ' . $value;
   }
 
 }
diff --git a/core/tests/Drupal/Tests/Core/Extension/RequiredModuleUninstallValidatorTest.php b/core/tests/Drupal/Tests/Core/Extension/RequiredModuleUninstallValidatorTest.php
index 718ba8f..a5f6fbb 100644
--- a/core/tests/Drupal/Tests/Core/Extension/RequiredModuleUninstallValidatorTest.php
+++ b/core/tests/Drupal/Tests/Core/Extension/RequiredModuleUninstallValidatorTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\Tests\Core\Extension;
 
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -72,7 +71,7 @@ public function testValidateRequired() {
       ->method('getModuleInfoByModule')
       ->willReturn(['required' => TRUE, 'name' => $module]);
 
-    $expected = [SafeMarkup::format('The @module module is required', ['@module' => $module])];
+    $expected = ["The $module module is required"];
     $reasons = $this->uninstallValidator->validate($module);
     $this->assertSame($expected, $reasons);
   }
diff --git a/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php b/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php
index e846b8d..1cef375 100644
--- a/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php
+++ b/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php
@@ -427,9 +427,9 @@ public function testSetCacheAuthUser() {
    * @covers ::setCache
    */
   public function testSetCacheWithSafeStrings() {
-    // A call to SafeMarkup::set() is appropriate in this test as a way to add a
-    // string to the safe list in the simplest way possible. Normally, avoid it.
-    SafeMarkup::set('a_safe_string');
+    // A call to SafeMarkup::format() is appropriate in this test as a way to
+    // add a string to the safe list in the simplest way possible.
+    SafeMarkup::format('@value', ['@value' => 'a_safe_string']);
     $form_build_id = 'the_form_build_id';
     $form = [
       '#form_id' => 'the_form_id'
diff --git a/core/tests/Drupal/Tests/Core/Form/FormValidatorTest.php b/core/tests/Drupal/Tests/Core/Form/FormValidatorTest.php
index d701991..5fe5a09 100644
--- a/core/tests/Drupal/Tests/Core/Form/FormValidatorTest.php
+++ b/core/tests/Drupal/Tests/Core/Form/FormValidatorTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\Tests\Core\Form;
 
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Form\FormState;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\HttpFoundation\Request;
@@ -468,7 +467,7 @@ public function providerTestPerformRequiredValidation() {
           '#maxlength' => 7,
           '#value' => $this->randomMachineName(8),
         ),
-        SafeMarkup::format('!name cannot be longer than %max characters but is currently %length characters long.', array('!name' => 'Test', '%max' => '7', '%length' => 8)),
+        'Test cannot be longer than <em class="placeholder">7</em> characters but is currently <em class="placeholder">8</em> characters long.',
         FALSE,
       ),
     );
diff --git a/core/tests/Drupal/Tests/Core/Path/PathMatcherTest.php b/core/tests/Drupal/Tests/Core/Path/PathMatcherTest.php
index 34d04c2..e361bf5 100644
--- a/core/tests/Drupal/Tests/Core/Path/PathMatcherTest.php
+++ b/core/tests/Drupal/Tests/Core/Path/PathMatcherTest.php
@@ -7,7 +7,6 @@
 
 namespace Drupal\Tests\Core\Path;
 
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Path\PathMatcher;
 use Drupal\Tests\UnitTestCase;
 
@@ -49,12 +48,7 @@ protected function setUp() {
   public function testMatchPath($patterns, $paths) {
     foreach ($paths as $path => $expected_result) {
       $actual_result = $this->pathMatcher->matchPath($path, $patterns);
-      $this->assertEquals($actual_result, $expected_result, SafeMarkup::format('Tried matching the path <code>@path</code> to the pattern <pre>@patterns</pre> - expected @expected, got @actual.', array(
-        '@path' => $path,
-        '@patterns' => $patterns,
-        '@expected' => var_export($expected_result, TRUE),
-        '@actual' => var_export($actual_result, TRUE),
-      )));
+      $this->assertEquals($actual_result, $expected_result, "Tried matching the path '$path' to the pattern '$patterns'.");
     }
   }
 
diff --git a/core/tests/Drupal/Tests/Core/Render/RendererPlaceholdersTest.php b/core/tests/Drupal/Tests/Core/Render/RendererPlaceholdersTest.php
index 43d3fe3..ef120c5 100644
--- a/core/tests/Drupal/Tests/Core/Render/RendererPlaceholdersTest.php
+++ b/core/tests/Drupal/Tests/Core/Render/RendererPlaceholdersTest.php
@@ -8,9 +8,9 @@
 namespace Drupal\Tests\Core\Render;
 
 use Drupal\Component\Utility\Html;
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Render\SafeString;
 
 /**
  * @coversDefaultClass \Drupal\Core\Render\Renderer
@@ -69,11 +69,10 @@ public function providerPlaceholders() {
         $token_render_array['#cache']['keys'] = $cache_keys;
       }
       $token = hash('crc32b', serialize($token_render_array));
-      return SafeMarkup::format('<drupal-render-placeholder callback="@callback" arguments="@arguments" token="@token"></drupal-render-placeholder>', [
-        '@callback' => 'Drupal\Tests\Core\Render\PlaceholdersTest::callback',
-        '@arguments' => '0=' . $args[0],
-        '@token' => $token,
-      ]);
+      // \Drupal\Core\Render\SafeString::create() is necessary as the render
+      // system would mangle this markup. Since this is exactly what happens at
+      // runtime this is a valid use-case.
+      return SafeString::create('<drupal-render-placeholder callback="Drupal\Tests\Core\Render\PlaceholdersTest::callback" arguments="' . '0=' . $args[0] . '" token="' . $token . '"></drupal-render-placeholder>');
     };
 
     $extract_placeholder_render_array = function ($placeholder_render_array) {
@@ -151,7 +150,7 @@ public function providerPlaceholders() {
           'foo' => 'bar',
         ],
         'placeholders' => [
-          $generate_placeholder_markup() => [
+          (string) $generate_placeholder_markup() => [
             '#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
           ],
         ],
@@ -318,8 +317,8 @@ public function providerPlaceholders() {
     // - manually created
     // - uncacheable
     $x = $base_element_b;
-    $expected_placeholder_render_array = $x['#attached']['placeholders'][$generate_placeholder_markup()];
-    unset($x['#attached']['placeholders'][$generate_placeholder_markup()]['#cache']);
+    $expected_placeholder_render_array = $x['#attached']['placeholders'][(string) $generate_placeholder_markup()];
+    unset($x['#attached']['placeholders'][(string) $generate_placeholder_markup()]['#cache']);
     $cases[] = [
       $x,
       $args,
@@ -333,6 +332,7 @@ public function providerPlaceholders() {
     // - cacheable
     $x = $base_element_b;
     $x['#markup'] = $placeholder_markup = $generate_placeholder_markup($keys);
+    $placeholder_markup = (string) $placeholder_markup;
     $x['#attached']['placeholders'] = [
       $placeholder_markup => [
         '#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
diff --git a/core/tests/Drupal/Tests/Core/Transliteration/PhpTransliterationTest.php b/core/tests/Drupal/Tests/Core/Transliteration/PhpTransliterationTest.php
index c975551..6788011 100644
--- a/core/tests/Drupal/Tests/Core/Transliteration/PhpTransliterationTest.php
+++ b/core/tests/Drupal/Tests/Core/Transliteration/PhpTransliterationTest.php
@@ -8,7 +8,6 @@
 namespace Drupal\Tests\Core\Transliteration;
 
 use Drupal\Component\Utility\Random;
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\Transliteration\PhpTransliteration;
 use Drupal\Tests\UnitTestCase;
 
@@ -59,12 +58,7 @@ public function testPhpTransliterationWithAlter($langcode, $original, $expected,
     $transliteration = new PhpTransliteration(NULL, $module_handler);
 
     $actual = $transliteration->transliterate($original, $langcode);
-    $this->assertSame($expected, $actual, SafeMarkup::format('@original transliteration to @actual is identical to @expected for language @langcode in service instance.', array(
-      '@original' => $printable,
-      '@langcode' => $langcode,
-      '@expected' => $expected,
-      '@actual' => $actual,
-    )));
+    $this->assertSame($expected, $actual, "'$printable' transliteration to '$actual' is identical to '$expected' for language '$langcode' in service instance.");
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php b/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php
index 9392d22..91b8fcc 100644
--- a/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php
+++ b/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php
@@ -7,10 +7,10 @@
 
 namespace Drupal\Tests\Core\Utility {
 
-use Drupal\Component\Utility\SafeMarkup;
 use Drupal\Core\GeneratedUrl;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Link;
+use Drupal\Core\Render\SafeString;
 use Drupal\Core\Url;
 use Drupal\Core\Utility\LinkGenerator;
 use Drupal\Tests\UnitTestCase;
@@ -376,7 +376,7 @@ public function testGenerateWithHtml() {
     // between SafeMarkup and the LinkGenerator.
     $url = new Url('test_route_5', array());
     $url->setUrlGenerator($this->urlGenerator);
-    $result = $this->linkGenerator->generate(SafeMarkup::set('<em>HTML output</em>'), $url);
+    $result = $this->linkGenerator->generate(SafeString::create('<em>HTML output</em>'), $url);
     $this->assertLink(array(
       'attributes' => array('href' => '/test-route-5'),
       'child' => array(
diff --git a/core/tests/Drupal/Tests/Standards/DrupalStandardsListener.php b/core/tests/Drupal/Tests/Listeners/DrupalStandardsListener.php
similarity index 98%
rename from core/tests/Drupal/Tests/Standards/DrupalStandardsListener.php
rename to core/tests/Drupal/Tests/Listeners/DrupalStandardsListener.php
index 59b2016..4bcc2e1 100644
--- a/core/tests/Drupal/Tests/Standards/DrupalStandardsListener.php
+++ b/core/tests/Drupal/Tests/Listeners/DrupalStandardsListener.php
@@ -2,13 +2,13 @@
 
 /**
  * @file
- * Contains \Drupal\Tests\Standards\DrupalStandardsListener.
+ * Contains \Drupal\Tests\Listeners\DrupalStandardsListener.
  *
  * Listener for PHPUnit tests, to enforce various coding standards within test
  * runs.
  */
 
-namespace Drupal\Tests\Standards;
+namespace Drupal\Tests\Listeners;
 
 /**
  * Listens for PHPUnit tests and fails those with invalid coverage annotations.
diff --git a/core/tests/Drupal/Tests/Listeners/SafeMarkupSideEffects.php b/core/tests/Drupal/Tests/Listeners/SafeMarkupSideEffects.php
new file mode 100644
index 0000000..54939cb
--- /dev/null
+++ b/core/tests/Drupal/Tests/Listeners/SafeMarkupSideEffects.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Listeners\SafeMarkupSideEffects.
+ *
+ * Listener for PHPUnit tests, to enforce that data providers don't add to the
+ * SafeMarkup static safe string list.
+ */
+
+namespace Drupal\Tests\Listeners;
+
+use Drupal\Component\Utility\SafeMarkup;
+
+/**
+ * Listens for PHPUnit tests and fails those with SafeMarkup side effects.
+ */
+class SafeMarkupSideEffects extends \PHPUnit_Framework_BaseTestListener {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function startTestSuite(\PHPUnit_Framework_TestSuite $suite) {
+    // Use a static so we only do this test once after all the data providers
+    // have run.
+    static $tested = FALSE;
+    if ($suite->getName() !== '' && !$tested) {
+      $tested = TRUE;
+      if (!empty(SafeMarkup::getAll())) {
+        throw new \RuntimeException('SafeMarkup string list polluted by data providers');
+      }
+    }
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php
index 67f7bcd..3433c94 100644
--- a/core/tests/Drupal/Tests/UnitTestCase.php
+++ b/core/tests/Drupal/Tests/UnitTestCase.php
@@ -48,6 +48,12 @@ protected function setUp() {
     FileCacheFactory::setConfiguration(['default' => ['class' => '\Drupal\Component\FileCache\NullFileCache']]);
 
     $this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
+
+    // Reset the static list of SafeStrings to prevent bleeding between tests.
+    $reflected_class = new \ReflectionClass('\Drupal\Component\Utility\SafeMarkup');
+    $reflected_property = $reflected_class->getProperty('safeStrings');
+    $reflected_property->setAccessible(true);
+    $reflected_property->setValue([]);
   }
 
   /**
