diff --git a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
index c085d4ec6bc2ed59cd0d3202bfec7c1146afdf95..3154b7f0d0e73afa348ac1acfa019d0cb9c26d90 100644
--- a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
+++ b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
@@ -6,6 +6,9 @@
 use Drupal\Component\Render\FormattableMarkup;
 use Drupal\Component\Utility\Environment;
 use Drupal\Core\Config\Development\ConfigSchemaChecker;
+use Drupal\Core\Config\FileStorage;
+use Drupal\Core\Config\InstallStorage;
+use Drupal\Core\Config\StorageInterface;
 use Drupal\Core\Database\Database;
 use Drupal\Core\DrupalKernel;
 use Drupal\Core\Extension\MissingDependencyException;
@@ -403,6 +406,48 @@ protected function initKernel(Request $request) {
     return $this->kernel->getContainer();
   }
 
+  /**
+   * Installs the default theme defined by `static::$defaultTheme` when needed.
+   *
+   * To install a test theme outside of the testing environment, add
+   * @code
+   * $settings['extension_discovery_scan_tests'] = TRUE;
+   * @endcode
+   * to your settings.php.
+   *
+   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
+   *   The container.
+   */
+  protected function installDefaultThemeFromClassProperty(ContainerInterface $container) {
+    // Use the install profile to determine the default theme if configured and
+    // not already specified.
+    $profile = $container->getParameter('install_profile');
+    $default_install_path = drupal_get_path('profile', $profile) . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY;
+    $profile_config_storage = new FileStorage($default_install_path, StorageInterface::DEFAULT_COLLECTION);
+    if (!isset($this->defaultTheme) && $profile_config_storage->exists('system.theme')) {
+      $this->defaultTheme = $profile_config_storage->read('system.theme')['default'];
+    }
+
+    // Require a default theme to be specified at this point.
+    if (!isset($this->defaultTheme)) {
+      // For backwards compatibility, tests using the 'testing' install profile
+      // on Drupal 8 automatically get 'classy' set, and other profiles use
+      // 'stark'.
+      @trigger_error('Drupal\Tests\BrowserTestBase::$defaultTheme is required in drupal:9.0.0 when using an install profile that does not set a default theme. See https://www.drupal.org/node/2352949, which includes recommendations on which theme to use.', E_USER_DEPRECATED);
+      $this->defaultTheme = $profile === 'testing' ? 'classy' : 'stark';
+    }
+
+    // Ensure the default theme is installed.
+    $container->get('theme_installer')->install([$this->defaultTheme], TRUE);
+
+    $system_theme_config = $container->get('config.factory')->getEditable('system.theme');
+    if ($system_theme_config->get('default') !== $this->defaultTheme) {
+      $system_theme_config
+        ->set('default', $this->defaultTheme)
+        ->save();
+    }
+  }
+
   /**
    * Install modules defined by `static::$modules`.
    *
diff --git a/core/modules/block_content/tests/src/Functional/BlockContentTypeTest.php b/core/modules/block_content/tests/src/Functional/BlockContentTypeTest.php
index bd3695cae398f79b63b179d5762dea16927ccb9f..452bea07863eaf6c4394ef4824b9d921e94c63eb 100644
--- a/core/modules/block_content/tests/src/Functional/BlockContentTypeTest.php
+++ b/core/modules/block_content/tests/src/Functional/BlockContentTypeTest.php
@@ -197,6 +197,7 @@ public function testsBlockContentAddTypes() {
     foreach (['bartik', 'seven', 'stark'] as $default_theme) {
       // Change the default theme.
       $theme_settings->set('default', $default_theme)->save();
+      $this->drupalPlaceBlock('local_actions_block');
       \Drupal::service('router.builder')->rebuild();
 
       // For each installed theme, go to its block page and test the redirects.
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index 3f0ab2ff131f20198671541f4ba0d3a28f7bb8ba..d86aa3f252d76112a3cc7d595b609e475b24d33c 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -392,6 +392,8 @@ protected function setUp() {
     // Initialize and override certain configurations.
     $this->initConfig($container);
 
+    $this->installDefaultThemeFromClassProperty($container);
+
     // Collect modules to install.
     $this->installModulesFromClassProperty($container);
 
diff --git a/core/modules/system/tests/src/Functional/System/ThemeTest.php b/core/modules/system/tests/src/Functional/System/ThemeTest.php
index 0b6fb81bf4ef8aadbcadd4d474f02fcf8d3d4694..2fa4d917bd5e8c41ce94ce51a6a0a3046d6dad76 100644
--- a/core/modules/system/tests/src/Functional/System/ThemeTest.php
+++ b/core/modules/system/tests/src/Functional/System/ThemeTest.php
@@ -334,6 +334,7 @@ public function testSwitchDefaultTheme() {
     // First, install Stark and set it as the default theme programmatically.
     $theme_installer->install(['stark']);
     $this->config('system.theme')->set('default', 'stark')->save();
+    $this->drupalPlaceBlock('local_tasks_block');
 
     // Install Bartik and set it as the default theme.
     $theme_installer->install(['bartik']);
diff --git a/core/profiles/testing/config/install/system.theme.yml b/core/profiles/testing/config/install/system.theme.yml
deleted file mode 100644
index 0defc7eaec43d95c414943c7e84cb19d137ba1de..0000000000000000000000000000000000000000
--- a/core/profiles/testing/config/install/system.theme.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-# @todo: Remove this file in https://www.drupal.org/node/2352949
-default: classy
diff --git a/core/profiles/testing/testing.info.yml b/core/profiles/testing/testing.info.yml
index 9924817a3d6ff867acb34ec8ee64f6bc704c367c..834198a7436625090eb05dbb5af00fc2db405c97 100644
--- a/core/profiles/testing/testing.info.yml
+++ b/core/profiles/testing/testing.info.yml
@@ -9,6 +9,3 @@ install:
   # tests as possible run with them enabled.
   - drupal:page_cache
   - dynamic_page_cache
-# @todo: Remove this in https://www.drupal.org/node/2352949
-themes:
-  - classy
diff --git a/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php b/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
index eaccc1bdf22b72475dba9c774c63e7dbaf8eb7f8..a41eea79d833a0d7451a3453445c6a96d22f20fc 100644
--- a/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
+++ b/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
@@ -191,6 +191,8 @@ protected function setUp() {
         ->getEditable('system.mail')
         ->set('interface.default', 'test_mail_collector')
         ->save();
+
+      $this->installDefaultThemeFromClassProperty($this->container);
     }
   }
 
diff --git a/core/tests/Drupal/TestSite/Commands/TestSiteInstallCommand.php b/core/tests/Drupal/TestSite/Commands/TestSiteInstallCommand.php
index d020304018ab36c9ce64a1d68c322b578534ac17..0764c7ed0a4b7175397e41d4b9b9640e5adb1cdd 100644
--- a/core/tests/Drupal/TestSite/Commands/TestSiteInstallCommand.php
+++ b/core/tests/Drupal/TestSite/Commands/TestSiteInstallCommand.php
@@ -198,6 +198,7 @@ protected function installDrupal() {
     $this->initSettings();
     $container = $this->initKernel(\Drupal::request());
     $this->initConfig($container);
+    $this->installDefaultThemeFromClassProperty($container);
     $this->installModulesFromClassProperty($container);
     $this->rebuildAll();
   }
diff --git a/core/tests/Drupal/Tests/BrowserTestBase.php b/core/tests/Drupal/Tests/BrowserTestBase.php
index 2b1ee867b1d5f1e79b29ee420f82f24ba422d3da..759b6033eabb22a3a1ad6ba504844a570bde67c5 100644
--- a/core/tests/Drupal/Tests/BrowserTestBase.php
+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -114,6 +114,15 @@ abstract class BrowserTestBase extends TestCase {
    */
   protected $profile = 'testing';
 
+  /**
+   * The theme to install as the default for testing.
+   *
+   * Defaults to the install profile's default theme, if it specifies any.
+   *
+   * @var string
+   */
+  protected $defaultTheme;
+
   /**
    * An array of custom translations suitable for drupal_rewrite_settings().
    *
@@ -557,6 +566,7 @@ public function installDrupal() {
     $this->initSettings();
     $container = $this->initKernel(\Drupal::request());
     $this->initConfig($container);
+    $this->installDefaultThemeFromClassProperty($container);
     $this->installModulesFromClassProperty($container);
     $this->rebuildAll();
   }
diff --git a/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php b/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php
index 3c76756bd5fb0f415f56ac3a5336b2d208f54a66..f9e346ac4c2c01ea9723531d4ba7e44409bbdbdd 100644
--- a/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php
+++ b/core/tests/Drupal/Tests/Listeners/DeprecationListenerTrait.php
@@ -140,6 +140,8 @@ public static function getSkippedDeprecations() {
       // This deprecation comes from behat/mink-browserkit-driver when updating
       // symfony/browser-kit to 4.3+.
       'The "Symfony\Component\BrowserKit\Response::getStatus()" method is deprecated since Symfony 4.3, use getStatusCode() instead.',
+      // @todo Remove in https://www.drupal.org/project/drupal/issues/3082655
+      'Drupal\Tests\BrowserTestBase::$defaultTheme is required in drupal:9.0.0 when using an install profile that does not set a default theme. See https://www.drupal.org/node/2352949, which includes recommendations on which theme to use.',
     ];
   }