diff --git a/core/modules/color/color.module b/core/modules/color/color.module
index 8a8aa5e..32ea150 100644
--- a/core/modules/color/color.module
+++ b/core/modules/color/color.module
@@ -6,13 +6,7 @@
  */
 
 use Drupal\Core\Url;
-use Drupal\Component\Utility\Bytes;
-use Drupal\Component\Utility\Color;
-use Drupal\Component\Utility\Environment;
-use Drupal\Core\Asset\CssOptimizer;
 use Drupal\Core\Block\BlockPluginInterface;
-use Drupal\Core\File\Exception\FileException;
-use Drupal\Core\File\FileSystemInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Render\Element\Textfield;
@@ -77,8 +71,8 @@ function color_form_system_theme_settings_alter(&$form, FormStateInterface $form
 function color_library_info_alter(&$libraries, $extension) {
   $themes = array_keys(\Drupal::service('theme_handler')->listInfo());
   if (in_array($extension, $themes)) {
-    $color_paths = \Drupal::config('color.theme.' . $extension)->get('stylesheets');
-    if (!empty($color_paths)) {
+    if ($paths = \Drupal::service('color.theme_decorator')->getThemeFiles($extension)) {
+      $color_paths = $paths['css'];
       foreach (array_keys($libraries) as $name) {
         if (isset($libraries[$name]['css'])) {
           // Override stylesheets.
@@ -155,26 +149,6 @@ function color_get_info($theme) {
 }
 
 /**
- * Retrieves the color palette for a particular theme.
- */
-function color_get_palette($theme, $default = FALSE) {
-  // Fetch and expand default palette.
-  $info = color_get_info($theme);
-  $palette = $info['schemes']['default']['colors'];
-
-  if ($default) {
-    return $palette;
-  }
-
-  // Load variable.
-  // @todo Default color config should be moved to yaml in the theme.
-  // Getting a mutable override-free object because this function is only used
-  // in forms. Color configuration is used to write CSS to the file system
-  // making configuration overrides pointless.
-  return \Drupal::configFactory()->getEditable('color.theme.' . $theme)->get('palette') ?: $palette;
-}
-
-/**
  * Form constructor for the color configuration form for a particular theme.
  *
  * @param $theme
@@ -218,7 +192,7 @@ function color_scheme_form($complete_form, FormStateInterface $form_state, $them
   }
 
   // Add scheme selector.
-  $default_palette = color_get_palette($theme, TRUE);
+  $default_palette = \Drupal::service('color.theme_decorator')->getPalette($theme, TRUE);
   $form['scheme'] = [
     '#type' => 'select',
     '#title' => t('Color set'),
@@ -363,22 +337,28 @@ function color_scheme_form_validate($form, FormStateInterface $form_state) {
  * @see color_scheme_form_validate()
  */
 function color_scheme_form_submit($form, FormStateInterface $form_state) {
-
-  // Avoid color settings spilling over to theme settings.
-  $color_settings = ['theme', 'palette', 'scheme'];
-  if ($form_state->hasValue('info')) {
-    $color_settings[] = 'info';
-  }
-  foreach ($color_settings as $setting_name) {
-    ${$setting_name} = $form_state->getValue($setting_name);
-    $form_state->unsetValue($setting_name);
-  }
-  if (!isset($info)) {
+  if (!$form_state->hasValue('info')) {
     return;
   }
+  $theme = $form_state->getValue('theme');
+  $palette = $form_state->getValue('palette');
+  $scheme = $form_state->getValue('scheme');
+  $info = $form_state->getValue('info');
+
+  // Avoid color settings spilling over to theme settings.
+  $form_state->unsetValue('theme');
+  $form_state->unsetValue('palette');
+  $form_state->unsetValue('scheme');
+  $form_state->unsetValue('info');
 
   $config = \Drupal::configFactory()->getEditable('color.theme.' . $theme);
 
+  // We don't need to store anything in config in case of default schema.
+  if ($scheme == 'default') {
+    $config->delete();
+    return;
+  }
+
   // Resolve palette.
   if ($scheme != '') {
     foreach ($palette as $key => $color) {
@@ -389,463 +369,26 @@ function color_scheme_form_submit($form, FormStateInterface $form_state) {
     $palette += $info['schemes']['default']['colors'];
   }
 
-  // Make sure enough memory is available.
-  if (isset($info['base_image'])) {
-    // Fetch source image dimensions.
-    $source = \Drupal::service('extension.list.theme')->getPath($theme) . '/' . $info['base_image'];
-    [$width, $height] = getimagesize($source);
-
-    // We need at least a copy of the source and a target buffer of the same
-    // size (both at 32bpp).
-    $required = $width * $height * 8;
-    // We intend to prevent color scheme changes if there isn't enough memory
-    // available.  memory_get_usage(TRUE) returns a more accurate number than
-    // memory_get_usage(), therefore we won't inadvertently reject a color
-    // scheme change based on a faulty memory calculation.
-    $usage = memory_get_usage(TRUE);
-    $memory_limit = ini_get('memory_limit');
-    $size = Bytes::toNumber($memory_limit);
-    if (!Environment::checkMemoryLimit($usage + $required, $memory_limit)) {
-      \Drupal::messenger()->addError(t('There is not enough memory available to PHP to change this theme\'s color scheme. You need at least %size more. Check the <a href="http://php.net/manual/ini.core.php#ini.sect.resource-limits">PHP documentation</a> for more information.', ['%size' => format_size($usage + $required - $size)]));
-      return;
-    }
-  }
-
-  $file_system = \Drupal::service('file_system');
-  // Delete old files.
-  $files = $config->get('files');
-  if (isset($files)) {
-    foreach ($files as $file) {
-      @$file_system->unlink($file);
-    }
-  }
-  if (isset($file) && $file = dirname($file)) {
-    @\Drupal::service('file_system')->rmdir($file);
-  }
+  // Saving config will trigger ColorConfigCacheInvalidator, which will
+  // invalidating library_info cache tag, which will then trigger deleting
+  // generated files via ColorCacheTagsInvalidator.
+  // The rebuilding of these files and a corresponding cache entry will then
+  // be triggered by color_block_view_pre_render and color_library_info_alter.
+  // Note that there may be multiple overrides of this config varying e.g. by
+  // domain, so there may be multiple file collections and multiple cache
+  // entries. If you implement varying overrides of this config item, be sure
+  // to add a corresponding cache context, which will then be picked up by
+  // \Drupal::service('color.theme_decorator')->getHash(), so different
+  // color settings will go into different file directories and cache entries.
 
-  // No change in color config, use the standard theme from color.inc.
-  if (implode(',', color_get_palette($theme, TRUE)) == implode(',', $palette)) {
-    $config->delete();
-    return;
-  }
-
-  // Prepare target locations for generated files.
-  $id = $theme . '-' . substr(hash('sha256', serialize($palette) . microtime()), 0, 8);
-  $paths['color'] = 'public://color';
-  $paths['target'] = $paths['color'] . '/' . $id;
-  /** @var \Drupal\Core\File\FileSystemInterface $file_system */
-  $file_system = \Drupal::service('file_system');
-  foreach ($paths as $path) {
-    $file_system->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY);
-  }
-  $paths['target'] = $paths['target'] . '/';
-  $paths['id'] = $id;
-  $paths['source'] = \Drupal::service('extension.list.theme')->getPath($theme) . '/';
-  $paths['files'] = $paths['map'] = [];
-
-  // Save palette and logo location.
   $config
     ->set('palette', $palette)
-    ->set('logo', $paths['target'] . 'logo.svg')
     ->save();
-
-  // Copy over neutral images.
-  /** @var \Drupal\Core\File\FileSystemInterface $file_system */
-  $file_system = \Drupal::service('file_system');
-  foreach ($info['copy'] as $file) {
-    $base = $file_system->basename($file);
-    $source = $paths['source'] . $file;
-    try {
-      $filepath = $file_system->copy($source, $paths['target'] . $base);
-    }
-    catch (FileException $e) {
-      $filepath = FALSE;
-    }
-    $paths['map'][$file] = $base;
-    $paths['files'][] = $filepath;
-  }
-
-  // Render new images, if image has been provided.
-  if (isset($info['base_image'])) {
-    _color_render_images($theme, $info, $paths, $palette);
-  }
-
-  // Rewrite theme stylesheets.
-  $css = [];
-  foreach ($info['css'] as $stylesheet) {
-    // Build a temporary array with CSS files.
-    $files = [];
-    if (file_exists($paths['source'] . $stylesheet)) {
-      $files[] = $stylesheet;
-    }
-
-    foreach ($files as $file) {
-      $css_optimizer = new CssOptimizer(\Drupal::service('file_url_generator'));
-      // Aggregate @imports recursively for each configured top level CSS file
-      // without optimization. Aggregation and optimization will be
-      // handled by drupal_build_css_cache() only.
-      $style = $css_optimizer->loadFile($paths['source'] . $file, FALSE);
-
-      // Return the path to where this CSS file originated from, stripping
-      // off the name of the file at the end of the path.
-      $css_optimizer->rewriteFileURIBasePath = base_path() . dirname($paths['source'] . $file) . '/';
-
-      // Prefix all paths within this CSS file, ignoring absolute paths.
-      $style = preg_replace_callback('/url\([\'"]?(?![a-z]+:|\/+)([^\'")]+)[\'"]?\)/i', [$css_optimizer, 'rewriteFileURI'], $style);
-
-      // Rewrite stylesheet with new colors.
-      $style = _color_rewrite_stylesheet($theme, $info, $paths, $palette, $style);
-      $base_file = $file_system->basename($file);
-      $css[] = $paths['target'] . $base_file;
-      _color_save_stylesheet($paths['target'] . $base_file, $style, $paths);
-    }
-  }
-
-  // Maintain list of files.
-  $config
-    ->set('stylesheets', $css)
-    ->set('files', $paths['files'])
-    ->save();
-}
-
-/**
- * Rewrites the stylesheet to match the colors in the palette.
- */
-function _color_rewrite_stylesheet($theme, &$info, &$paths, $palette, $style) {
-  // Prepare color conversion table.
-  $conversion = $palette;
-  foreach ($conversion as $k => $v) {
-    $v = mb_strtolower($v);
-    $conversion[$k] = Color::normalizeHexLength($v);
-  }
-  $default = color_get_palette($theme, TRUE);
-
-  // Split off the "Don't touch" section of the stylesheet.
-  $split = "Color Module: Don't touch";
-  if (strpos($style, $split) !== FALSE) {
-    [$style, $fixed] = explode($split, $style);
-  }
-
-  // Find all colors in the stylesheet and the chunks in between.
-  $style = preg_split('/(#[0-9a-f]{6}|#[0-9a-f]{3})/i', $style, -1, PREG_SPLIT_DELIM_CAPTURE);
-  $is_color = FALSE;
-  $output = '';
-  $base = 'base';
-
-  // Iterate over all the parts.
-  foreach ($style as $chunk) {
-    if ($is_color) {
-      $chunk = mb_strtolower($chunk);
-      $chunk = Color::normalizeHexLength($chunk);
-      // Check if this is one of the colors in the default palette.
-      if ($key = array_search($chunk, $default)) {
-        $chunk = $conversion[$key];
-      }
-      // Not a pre-set color. Extrapolate from the base.
-      else {
-        $chunk = _color_shift($palette[$base], $default[$base], $chunk, $info['blend_target']);
-      }
-    }
-    else {
-      // Determine the most suitable base color for the next color.
-
-      // 'a' declarations. Use link.
-      if (preg_match('@[^a-z0-9_-](a)[^a-z0-9_-][^/{]*{[^{]+$@i', $chunk)) {
-        $base = 'link';
-      }
-      // 'color:' styles. Use text.
-      elseif (preg_match('/(?<!-)color[^{:]*:[^{#]*$/i', $chunk)) {
-        $base = 'text';
-      }
-      // Reset back to base.
-      else {
-        $base = 'base';
-      }
-    }
-    $output .= $chunk;
-    $is_color = !$is_color;
-  }
-  // Append fixed colors segment.
-  if (isset($fixed)) {
-    $output .= $fixed;
-  }
-
-  // Replace paths to images.
-  foreach ($paths['map'] as $before => $after) {
-    $before = base_path() . $paths['source'] . $before;
-    $before = preg_replace('`(^|/)(?!../)([^/]+)/../`', '$1', $before);
-    $output = str_replace($before, $after, $output);
-  }
-
-  return $output;
-}
-
-/**
- * Saves the rewritten stylesheet to disk.
- */
-function _color_save_stylesheet($file, $style, &$paths) {
-  $filepath = \Drupal::service('file_system')->saveData($style, $file, FileSystemInterface::EXISTS_REPLACE);
-  $paths['files'][] = $filepath;
-
-  // Set standard file permissions for webserver-generated files.
-  \Drupal::service('file_system')->chmod($file);
-}
-
-/**
- * Renders images that match a given palette.
- */
-function _color_render_images($theme, &$info, &$paths, $palette) {
-  // Prepare template image.
-  $source = $paths['source'] . '/' . $info['base_image'];
-  $source = imagecreatefrompng($source);
-  $width = imagesx($source);
-  $height = imagesy($source);
-
-  // Prepare target buffer.
-  $target = imagecreatetruecolor($width, $height);
-  imagealphablending($target, TRUE);
-
-  // Fill regions of solid color.
-  foreach ($info['fill'] as $color => $fill) {
-    imagefilledrectangle($target, $fill[0], $fill[1], $fill[0] + $fill[2], $fill[1] + $fill[3], _color_gd($target, $palette[$color]));
-  }
-
-  // Render gradients.
-  foreach ($info['gradients'] as $gradient) {
-    // Get direction of the gradient.
-    if (isset($gradient['direction']) && $gradient['direction'] == 'horizontal') {
-      // Horizontal gradient.
-      for ($x = 0; $x < $gradient['dimension'][2]; $x++) {
-        $color = _color_blend($target, $palette[$gradient['colors'][0]], $palette[$gradient['colors'][1]], $x / ($gradient['dimension'][2] - 1));
-        imagefilledrectangle($target, ($gradient['dimension'][0] + $x), $gradient['dimension'][1], ($gradient['dimension'][0] + $x + 1), ($gradient['dimension'][1] + $gradient['dimension'][3]), $color);
-      }
-    }
-    else {
-      // Vertical gradient.
-      for ($y = 0; $y < $gradient['dimension'][3]; $y++) {
-        $color = _color_blend($target, $palette[$gradient['colors'][0]], $palette[$gradient['colors'][1]], $y / ($gradient['dimension'][3] - 1));
-        imagefilledrectangle($target, $gradient['dimension'][0], $gradient['dimension'][1] + $y, $gradient['dimension'][0] + $gradient['dimension'][2], $gradient['dimension'][1] + $y + 1, $color);
-      }
-    }
-  }
-
-  // Blend over template.
-  imagecopy($target, $source, 0, 0, 0, 0, $width, $height);
-
-  // Clean up template image.
-  imagedestroy($source);
-
-  // Cut out slices.
-  foreach ($info['slices'] as $file => $coord) {
-    [$x, $y, $width, $height] = $coord;
-    /** @var \Drupal\Core\File\FileSystemInterface $file_system */
-    $file_system = \Drupal::service('file_system');
-    $base = $file_system->basename($file);
-    $image = $file_system->realpath($paths['target'] . $base);
-
-    // Cut out slice.
-    if ($file == 'screenshot.png') {
-      $slice = imagecreatetruecolor(150, 90);
-      imagecopyresampled($slice, $target, 0, 0, $x, $y, 150, 90, $width, $height);
-      \Drupal::configFactory()->getEditable('color.theme.' . $theme)
-        ->set('screenshot', $image)
-        ->save();
-    }
-    else {
-      $slice = imagecreatetruecolor($width, $height);
-      imagecopy($slice, $target, 0, 0, $x, $y, $width, $height);
-    }
-
-    // Save image.
-    imagepng($slice, $image);
-    imagedestroy($slice);
-    $paths['files'][] = $image;
-
-    // Set standard file permissions for webserver-generated files.
-    $file_system->chmod($image);
-
-    // Build before/after map of image paths.
-    $paths['map'][$file] = $base;
-  }
-
-  // Clean up target buffer.
-  imagedestroy($target);
-}
-
-/**
- * Shifts a given color, using a reference pair and a target blend color.
- *
- * Note: this function is significantly different from the JS version, as it
- * is written to match the blended images perfectly.
- *
- * Constraint: if (ref2 == target + (ref1 - target) * delta) for some fraction
- * delta then (return == target + (given - target) * delta).
- *
- * Loose constraint: Preserve relative positions in saturation and luminance
- * space.
- */
-function _color_shift($given, $ref1, $ref2, $target) {
-  // We assume that ref2 is a blend of ref1 and target and find
-  // delta based on the length of the difference vectors.
-
-  // delta = 1 - |ref2 - ref1| / |white - ref1|
-  $target = _color_unpack($target, TRUE);
-  $ref1 = _color_unpack($ref1, TRUE);
-  $ref2 = _color_unpack($ref2, TRUE);
-  $numerator = 0;
-  $denominator = 0;
-  for ($i = 0; $i < 3; ++$i) {
-    $numerator += ($ref2[$i] - $ref1[$i]) * ($ref2[$i] - $ref1[$i]);
-    $denominator += ($target[$i] - $ref1[$i]) * ($target[$i] - $ref1[$i]);
-  }
-  $delta = ($denominator > 0) ? (1 - sqrt($numerator / $denominator)) : 0;
-
-  // Calculate the color that ref2 would be if the assumption was true.
-  for ($i = 0; $i < 3; ++$i) {
-    $ref3[$i] = $target[$i] + ($ref1[$i] - $target[$i]) * $delta;
-  }
-
-  // If the assumption is not true, there is a difference between ref2 and ref3.
-  // We measure this in HSL space. Notation: x' = hsl(x).
-  $ref2 = _color_rgb2hsl($ref2);
-  $ref3 = _color_rgb2hsl($ref3);
-  for ($i = 0; $i < 3; ++$i) {
-    $shift[$i] = $ref2[$i] - $ref3[$i];
-  }
-
-  // Take the given color, and blend it towards the target.
-  $given = _color_unpack($given, TRUE);
-  for ($i = 0; $i < 3; ++$i) {
-    $result[$i] = $target[$i] + ($given[$i] - $target[$i]) * $delta;
-  }
-
-  // Finally, we apply the extra shift in HSL space.
-  // Note: if ref2 is a pure blend of ref1 and target, then |shift| = 0.
-  $result = _color_rgb2hsl($result);
-  for ($i = 0; $i < 3; ++$i) {
-    $result[$i] = min(1, max(0, $result[$i] + $shift[$i]));
-  }
-  $result = _color_hsl2rgb($result);
-
-  // Return hex color.
-  return _color_pack($result, TRUE);
 }
 
 /**
- * Converts a hex triplet into a GD color.
+ * Implements hook_cache_flush().
  */
-function _color_gd($img, $hex) {
-  $c = array_merge([$img], _color_unpack($hex));
-  return call_user_func_array('imagecolorallocate', $c);
-}
-
-/**
- * Blends two hex colors and returns the GD color.
- */
-function _color_blend($img, $hex1, $hex2, $alpha) {
-  $in1 = _color_unpack($hex1);
-  $in2 = _color_unpack($hex2);
-  $out = [$img];
-  for ($i = 0; $i < 3; ++$i) {
-    $out[] = $in1[$i] + ($in2[$i] - $in1[$i]) * $alpha;
-  }
-
-  return call_user_func_array('imagecolorallocate', $out);
-}
-
-/**
- * Converts a hex color into an RGB triplet.
- */
-function _color_unpack($hex, $normalize = FALSE) {
-  $hex = substr($hex, 1);
-  if (strlen($hex) == 3) {
-    $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
-  }
-  $c = hexdec($hex);
-  for ($i = 16; $i >= 0; $i -= 8) {
-    $out[] = (($c >> $i) & 0xFF) / ($normalize ? 255 : 1);
-  }
-
-  return $out;
-}
-
-/**
- * Converts an RGB triplet to a hex color.
- */
-function _color_pack($rgb, $normalize = FALSE) {
-  $out = 0;
-  foreach ($rgb as $k => $v) {
-    $out |= ((int) ($v * ($normalize ? 255 : 1)) << (16 - $k * 8));
-  }
-
-  return '#' . str_pad(dechex($out), 6, 0, STR_PAD_LEFT);
-}
-
-/**
- * Converts an HSL triplet into RGB.
- */
-function _color_hsl2rgb($hsl) {
-  $h = $hsl[0];
-  $s = $hsl[1];
-  $l = $hsl[2];
-  $m2 = ($l <= 0.5) ? $l * ($s + 1) : $l + $s - $l * $s;
-  $m1 = $l * 2 - $m2;
-
-  return [
-    _color_hue2rgb($m1, $m2, $h + 0.33333),
-    _color_hue2rgb($m1, $m2, $h),
-    _color_hue2rgb($m1, $m2, $h - 0.33333),
-  ];
-}
-
-/**
- * Helper function for _color_hsl2rgb().
- */
-function _color_hue2rgb($m1, $m2, $h) {
-  $h = ($h < 0) ? $h + 1 : (($h > 1) ? $h - 1 : $h);
-  if ($h * 6 < 1) {
-    return $m1 + ($m2 - $m1) * $h * 6;
-  }
-  if ($h * 2 < 1) {
-    return $m2;
-  }
-  if ($h * 3 < 2) {
-    return $m1 + ($m2 - $m1) * (0.66666 - $h) * 6;
-  }
-
-  return $m1;
-}
-
-/**
- * Converts an RGB triplet to HSL.
- */
-function _color_rgb2hsl($rgb) {
-  $r = $rgb[0];
-  $g = $rgb[1];
-  $b = $rgb[2];
-  $min = min($r, min($g, $b));
-  $max = max($r, max($g, $b));
-  $delta = $max - $min;
-  $l = ($min + $max) / 2;
-  $s = 0;
-
-  if ($l > 0 && $l < 1) {
-    $s = $delta / ($l < 0.5 ? (2 * $l) : (2 - 2 * $l));
-  }
-
-  $h = 0;
-  if ($delta > 0) {
-    if ($max == $r && $max != $g) {
-      $h += ($g - $b) / $delta;
-    }
-    if ($max == $g && $max != $b) {
-      $h += (2 + ($b - $r) / $delta);
-    }
-    if ($max == $b && $max != $r) {
-      $h += (4 + ($r - $g) / $delta);
-    }
-    $h /= 6;
-  }
-
-  return [$h, $s, $l];
+function color_cache_flush() {
+  \Drupal::service('color.theme_decorator')->unlinkGeneratedFiles();
 }
diff --git a/core/modules/color/color.services.yml b/core/modules/color/color.services.yml
index 9575785..3a58d96 100644
--- a/core/modules/color/color.services.yml
+++ b/core/modules/color/color.services.yml
@@ -4,3 +4,8 @@ services:
     arguments: ['@cache_tags.invalidator']
     tags:
       - { name: event_subscriber }
+  color.theme_decorator:
+    class: Drupal\color\ColorThemeDecorator
+    arguments: ['@config.factory', '@file_system', '@cache.default', '@extension.list.theme', '@file_url_generator']
+    tags:
+      - { name: cache_tags_invalidator}
diff --git a/core/modules/color/config/schema/color.schema.yml b/core/modules/color/config/schema/color.schema.yml
index 07ae1cc..1cabf53 100644
--- a/core/modules/color/config/schema/color.schema.yml
+++ b/core/modules/color/config/schema/color.schema.yml
@@ -7,14 +7,3 @@ color.theme.*:
       label: 'Palette settings'
       sequence:
         type: color_hex
-    logo:
-      type: path
-      label: 'Logo path'
-    stylesheets:
-      type: sequence
-      sequence:
-        type: path
-    files:
-      type: sequence
-      sequence:
-        type: path
diff --git a/core/modules/color/migrations/d7_color.yml b/core/modules/color/migrations/d7_color.yml
index 9bc7af6..8861ae6 100644
--- a/core/modules/color/migrations/d7_color.yml
+++ b/core/modules/color/migrations/d7_color.yml
@@ -22,14 +22,17 @@ process:
       plugin: extract
       index:
         - 2
-  # Skip if the variable name ends in 'screenshot'.
-  screenshot:
+  # Skip if the variable name is old.
+  outdated:
     -
       plugin: static_map
       source: '@element_name'
       bypass: true
       map:
         screenshot: false
+        files: false
+        logo: false
+        stylesheets: false
     -
       plugin: skip_on_empty
       method: row
diff --git a/core/modules/color/src/ColorSystemBrandingBlockAlter.php b/core/modules/color/src/ColorSystemBrandingBlockAlter.php
index 337c6bc..d322aae 100644
--- a/core/modules/color/src/ColorSystemBrandingBlockAlter.php
+++ b/core/modules/color/src/ColorSystemBrandingBlockAlter.php
@@ -23,9 +23,9 @@ public static function preRender($build) {
       ->applyTo($build);
 
     // Override logo.
-    $logo = $config->get('logo');
-    if ($logo && $build['content']['site_logo'] && preg_match('!' . $theme_key . '/logo.svg$!', $build['content']['site_logo']['#uri'])) {
-      $build['content']['site_logo']['#uri'] = \Drupal::service('file_url_generator')->generateString($logo);
+    $paths = \Drupal::service('color.theme_decorator')->getThemeFiles($theme_key);
+    if (!empty($paths['logo']) && $build['content']['site_logo'] && preg_match('!' . $theme_key . '/logo.svg$!', $build['content']['site_logo']['#uri'])) {
+      $build['content']['site_logo']['#uri'] = \Drupal::service('file_url_generator')->generateString($paths['logo']);
     }
 
     return $build;
diff --git a/core/modules/color/src/ColorThemeDecorator.php b/core/modules/color/src/ColorThemeDecorator.php
new file mode 100644
index 0000000..dfda913
--- /dev/null
+++ b/core/modules/color/src/ColorThemeDecorator.php
@@ -0,0 +1,649 @@
+<?php
+
+namespace Drupal\color;
+
+use Drupal\Core\Asset\CssOptimizer;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Extension\ThemeExtensionList;
+use Drupal\Core\File\Exception\FileException;
+use Drupal\Core\File\FileSystemInterface;
+use Drupal\Component\Utility\Color;
+use Drupal\Core\File\FileUrlGeneratorInterface;
+
+/**
+ * Defines the color theme decorator service.
+ */
+class ColorThemeDecorator implements CacheTagsInvalidatorInterface {
+
+  /**
+   * The config factory interface.
+   *
+   * @var Drupal\Core\File\FileSystemInterface
+   */
+  protected $configFactory;
+
+  /**
+   * The file system interface.
+   *
+   * @var Drupal\Core\File\FileSystemInterface
+   */
+  protected $fileSystem;
+
+  /**
+   * The cache interface.
+   *
+   * @var Drupal\Core\Cache\CacheBackendInterface
+   */
+  protected $cache;
+
+  /**
+   * The theme extension list service.
+   *
+   * @var \Drupal\Core\Extension\ThemeExtensionList
+   */
+  protected $themeExtensionList;
+
+  /**
+   * The file url generator.
+   *
+   * @var \Drupal\Core\File\FileUrlGeneratorInterface
+   */
+  protected $fileUrlGenerator;
+
+  /**
+   * Constructor method.
+   *
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory interface.
+   * @param \Drupal\Core\File\FileSystemInterface $file_system
+   *   The file system interface.
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
+   *   The cache interface.
+   * @param \Drupal\Core\Extension\ThemeExtensionList $themeExtensionList
+   *   The theme extension list service.
+   * @param \Drupal\Core\File\FileUrlGeneratorInterface $fileUrlGenerator
+   *   The file url generator service.
+   */
+  public function __construct(ConfigFactoryInterface $config_factory, FileSystemInterface $file_system, CacheBackendInterface $cache, ThemeExtensionList $themeExtensionList, FileUrlGeneratorInterface $fileUrlGenerator) {
+    $this->configFactory = $config_factory;
+    $this->fileSystem = $file_system;
+    $this->cache = $cache;
+    $this->themeExtensionList = $themeExtensionList;
+    $this->fileUrlGenerator = $fileUrlGenerator;
+  }
+
+  /**
+   * Invalidate tags.
+   *
+   * If library_info is invalidated, delete our generated files.
+   *
+   * @param array $tags
+   *   The tags to invalidate.
+   */
+  public function invalidateTags(array $tags) {
+    if (in_array('library_info', $tags)) {
+      $this->unlinkGeneratedFiles();
+    }
+  }
+
+  /**
+   * Delete generated files.
+   */
+  public function unlinkGeneratedFiles() {
+    $dirPath = 'public://color';
+    if (is_dir($dirPath)) {
+      foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dirPath, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST) as $path) {
+        $path->isDir() && !$path->isLink() ? rmdir($path->getPathname()) : unlink($path->getPathname());
+      }
+    }
+  }
+
+  /**
+   * Get theme files.
+   *
+   * @param string $theme
+   *   The theme name.
+   */
+  public function getThemeFiles($theme) {
+    $config = $this->configFactory->get('color.theme.' . $theme);
+    $palette = $config->get('palette');
+    if (empty($palette)) {
+      return FALSE;
+    }
+    return $this->ensureFiles($theme, $palette, color_get_info($theme));
+  }
+
+  /**
+   * Generate files if needed.
+   *
+   * @param string $theme
+   *   The theme name.
+   * @param array|null $palette
+   *   The palette of color codes.
+   * @param array $info
+   *   Color info from the theme.
+   *
+   * @return array|null
+   *   An array of paths information, if available.
+   */
+  public function ensureFiles($theme, $palette, $info) {
+    if (!$palette) {
+      return NULL;
+    }
+    $hash = self::getHash($theme);
+    $cid = "color:paths:$hash";
+    if ($data = $this->cache->get($cid)) {
+      return $data->data;
+    }
+
+    // Prepare target locations for generated files.
+    $paths['color'] = 'public://color';
+    $paths['target'] = $paths['color'] . '/' . $hash;
+    foreach ($paths as $path) {
+      $this->fileSystem->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY);
+    }
+    $paths['target'] = $paths['target'] . '/';
+    $paths['id'] = $hash;
+    $paths['source'] = $this->themeExtensionList->getPath($theme) . '/';
+    $paths['files'] = $paths['map'] = [];
+
+    // Copy over neutral images.
+    foreach ($info['copy'] as $file) {
+      $base = $this->fileSystem->basename($file);
+      $source = $paths['source'] . $file;
+      try {
+        $filepath = $this->fileSystem->copy($source, $paths['target'] . $base);
+      }
+      catch (FileException $e) {
+        $filepath = FALSE;
+      }
+      $paths['map'][$file] = $base;
+      $paths['files'][] = $filepath;
+    }
+
+    // Render new images, if image has been provided.
+    if (isset($info['base_image'])) {
+      $this->renderImages($theme, $info, $paths, $palette);
+    }
+
+    // Rewrite theme stylesheets.
+    $paths['css'] = [];
+    foreach ($info['css'] as $stylesheet) {
+      $source_css = $paths['source'] . $stylesheet;
+      $target_css = $paths['target'] . $this->fileSystem->basename($stylesheet);
+      if (file_exists($source_css)) {
+        $css_optimizer = new CssOptimizer($this->fileUrlGenerator);
+        // Aggregate @imports recursively for each configured top level CSS file
+        // without optimization. Aggregation and optimization will be
+        // handled by drupal_build_css_cache() only.
+        $style = $css_optimizer->loadFile($source_css, FALSE);
+
+        // Return the path to where this CSS file originated from, stripping
+        // off the name of the file at the end of the path.
+        $css_optimizer->rewriteFileURIBasePath = base_path() . dirname($source_css) . '/';
+
+        // Prefix all paths within this CSS file, ignoring absolute paths.
+        $style = preg_replace_callback('/url\([\'"]?(?![a-z]+:|\/+)([^\'")]+)[\'"]?\)/i', [
+          $css_optimizer,
+          'rewriteFileURI',
+        ], $style);
+
+        // Rewrite stylesheet with new colors.
+        $style = $this->rewriteStyleSheet($theme, $info, $paths, $palette, $style);
+        $filepath = $this->fileSystem->saveData($style, $target_css, FileSystemInterface::EXISTS_REPLACE);
+        $this->fileSystem->chmod($target_css);
+      }
+      $paths['css'][] = $target_css;
+      $paths['files'][] = $filepath;
+    }
+    $this->cache->set($cid, $paths, CacheBackendInterface::CACHE_PERMANENT, ['library_info']);
+
+    return $paths;
+  }
+
+  /**
+   * Get a hash that varies on theme and config cache contexts.
+   *
+   * @param string $theme
+   *   The theme.
+   *
+   * @return string
+   *   The hash.
+   *
+   * @todo
+   *   Is it possible to replace "\Drupal::service('cache_contexts_manager')" to
+   *   something else?.
+   */
+  public static function getHash($theme) {
+    /** @var \Drupal\Core\Cache\Context\CacheContextsManager $cache_contexts_manager */
+    $cache_contexts_manager = \Drupal::service('cache_contexts_manager');
+    $config = \Drupal::configFactory()->get('color.theme.' . $theme);
+    $cache_contexts = array_merge(['theme'], $config->getCacheContexts());
+    $cache_context_keys = $cache_contexts_manager->convertTokensToKeys($cache_contexts)->getKeys();
+    $hash = hash('sha256', serialize($cache_context_keys));
+
+    return $hash;
+  }
+
+  /**
+   * Render images matching a given palette.
+   *
+   * @param string $theme
+   *   The theme name.
+   * @param array $info
+   *   The theme info.
+   * @param array $paths
+   *   The theme file paths.
+   * @param array $palette
+   *   Theme color palette.
+   */
+  private function renderImages($theme, &$info, &$paths, $palette) {
+    // Prepare template image.
+    $source = $paths['source'] . '/' . $info['base_image'];
+    $source = imagecreatefrompng($source);
+    $width = imagesx($source);
+    $height = imagesy($source);
+
+    // Prepare target buffer.
+    $target = imagecreatetruecolor($width, $height);
+    imagealphablending($target, TRUE);
+
+    // Fill regions of solid color.
+    foreach ($info['fill'] as $color => $fill) {
+      imagefilledrectangle($target, $fill[0], $fill[1], $fill[0] + $fill[2], $fill[1] + $fill[3], $this->gd($target, $palette[$color]));
+    }
+
+    // Render gradients.
+    foreach ($info['gradients'] as $gradient) {
+      // Get direction of the gradient.
+      if (isset($gradient['direction']) && $gradient['direction'] == 'horizontal') {
+        // Horizontal gradient.
+        for ($x = 0; $x < $gradient['dimension'][2]; $x++) {
+          $color = $this->blend($target, $palette[$gradient['colors'][0]], $palette[$gradient['colors'][1]], $x / ($gradient['dimension'][2] - 1));
+          imagefilledrectangle($target, ($gradient['dimension'][0] + $x), $gradient['dimension'][1], ($gradient['dimension'][0] + $x + 1), ($gradient['dimension'][1] + $gradient['dimension'][3]), $color);
+        }
+      }
+      else {
+        // Vertical gradient.
+        for ($y = 0; $y < $gradient['dimension'][3]; $y++) {
+          $color = $this->blend($target, $palette[$gradient['colors'][0]], $palette[$gradient['colors'][1]], $y / ($gradient['dimension'][3] - 1));
+          imagefilledrectangle($target, $gradient['dimension'][0], $gradient['dimension'][1] + $y, $gradient['dimension'][0] + $gradient['dimension'][2], $gradient['dimension'][1] + $y + 1, $color);
+        }
+      }
+    }
+
+    // Blend over template.
+    imagecopy($target, $source, 0, 0, 0, 0, $width, $height);
+
+    // Clean up template image.
+    imagedestroy($source);
+
+    // Cut out slices.
+    foreach ($info['slices'] as $file => $coord) {
+      list($x, $y, $width, $height) = $coord;
+      $base = $this->fileSystem->basename($file);
+      $image = $this->fileSystem->realpath($paths['target'] . $base);
+
+      // Cut out slice.
+      if ($file == 'screenshot.png') {
+        $slice = imagecreatetruecolor(150, 90);
+        imagecopyresampled($slice, $target, 0, 0, $x, $y, 150, 90, $width, $height);
+        $this->configFactory->getEditable('color.theme.' . $theme)
+          ->set('screenshot', $image)
+          ->save();
+      }
+      else {
+        $slice = imagecreatetruecolor($width, $height);
+        imagecopy($slice, $target, 0, 0, $x, $y, $width, $height);
+      }
+
+      // Save image.
+      imagepng($slice, $image);
+      imagedestroy($slice);
+      $paths['files'][] = $image;
+
+      // Set standard file permissions for webserver-generated files.
+      $this->fileSystem->chmod($image);
+
+      // Build before/after map of image paths.
+      $paths['map'][$file] = $base;
+    }
+
+    // Clean up target buffer.
+    imagedestroy($target);
+  }
+
+  /**
+   * Rewrites the stylesheet to match the colors in the palette.
+   *
+   * @param string $theme
+   *   The theme name.
+   * @param array $info
+   *   The theme info.
+   * @param array $paths
+   *   Theme file paths.
+   * @param array $palette
+   *   Colors to be used.
+   * @param string $style
+   *   Style to be used.
+   */
+  private function rewriteStyleSheet($theme, &$info, $paths, $palette, $style) {
+    // Prepare color conversion table.
+    $conversion = $palette;
+    foreach ($conversion as $k => $v) {
+      $v = mb_strtolower($v);
+      $conversion[$k] = Color::normalizeHexLength($v);
+    }
+    $default = $this->getPalette($theme, TRUE);
+
+    // Split off the "Don't touch" section of the stylesheet.
+    $split = "Color Module: Don't touch";
+    if (strpos($style, $split) !== FALSE) {
+      list($style, $fixed) = explode($split, $style);
+    }
+
+    // Find all colors in the stylesheet and the chunks in between.
+    $style = preg_split('/(#[0-9a-f]{6}|#[0-9a-f]{3})/i', $style, -1, PREG_SPLIT_DELIM_CAPTURE);
+    $is_color = FALSE;
+    $output = '';
+    $base = 'base';
+
+    // Iterate over all the parts.
+    foreach ($style as $chunk) {
+      if ($is_color) {
+        $chunk = mb_strtolower($chunk);
+        $chunk = Color::normalizeHexLength($chunk);
+        // Check if this is one of the colors in the default palette.
+        if ($key = array_search($chunk, $default)) {
+          $chunk = $conversion[$key];
+        }
+        // Not a pre-set color. Extrapolate from the base.
+        else {
+          $chunk = $this->shift($palette[$base], $default[$base], $chunk, $info['blend_target']);
+        }
+      }
+      else {
+        // Determine the most suitable base color for the next color.
+        // 'a' declarations. Use link.
+        if (preg_match('@[^a-z0-9_-](a)[^a-z0-9_-][^/{]*{[^{]+$@i', $chunk)) {
+          $base = 'link';
+        }
+        // 'color:' styles. Use text.
+        elseif (preg_match('/(?<!-)color[^{:]*:[^{#]*$/i', $chunk)) {
+          $base = 'text';
+        }
+        // Reset back to base.
+        else {
+          $base = 'base';
+        }
+      }
+      $output .= $chunk;
+      $is_color = !$is_color;
+    }
+    // Append fixed colors segment.
+    if (isset($fixed)) {
+      $output .= $fixed;
+    }
+
+    // Replace paths to images.
+    foreach ($paths['map'] as $before => $after) {
+      $before = base_path() . $paths['source'] . $before;
+      $before = preg_replace('`(^|/)(?!../)([^/]+)/../`', '$1', $before);
+      $output = str_replace($before, $after, $output);
+    }
+
+    return $output;
+  }
+
+  /**
+   * Retrieves the color palette for a particular theme.
+   *
+   * @param string $theme
+   *   The theme name.
+   * @param bool $default
+   *   Boolean indicating if default palette should be returned.
+   */
+  public function getPalette($theme, $default = FALSE) {
+    // Fetch and expand default palette.
+    $info = color_get_info($theme);
+    $palette = $info['schemes']['default']['colors'];
+
+    if ($default) {
+      return $palette;
+    }
+
+    // Load variable.
+    // @todo Default color config should be moved to yaml in the theme.
+    // Getting a mutable override-free object because this function is only used
+    // in forms. Color configuration is used to write CSS to the file system
+    // making configuration overrides pointless.
+    return $this->configFactory->getEditable('color.theme.' . $theme)->get('palette') ?: $palette;
+  }
+
+  /**
+   * Converts a hex triplet into a GD color.
+   *
+   * @param resource $img
+   *   The image to process.
+   * @param string $hex
+   *   The color in hexadecimal format.
+   */
+  private function gd($img, $hex) {
+    $c = array_merge([$img], $this->hexToRgb($hex));
+
+    return call_user_func_array('imagecolorallocate', $c);
+  }
+
+  /**
+   * Blends two hex colors and returns the GD color.
+   *
+   * @param resource $img
+   *   The image to process.
+   * @param string $hex1
+   *   The color in hexadecimal format.
+   * @param string $hex2
+   *   The color in hexadecimal format.
+   * @param string $alpha
+   *   The alpha.
+   */
+  private function blend($img, $hex1, $hex2, $alpha) {
+    $in1 = $this->hexToRgb($hex1);
+    $in2 = $this->hexToRgb($hex2);
+    $out = [$img];
+    for ($i = 0; $i < 3; ++$i) {
+      $out[] = $in1[$i] + ($in2[$i] - $in1[$i]) * $alpha;
+    }
+
+    return call_user_func_array('imagecolorallocate', $out);
+  }
+
+  /**
+   * Converts an RGB triplet to a hex color.
+   *
+   * @param string $rgb
+   *   The color in RGB format.
+   * @param bool $normalize
+   *   If color should be normalized.
+   */
+  public function rgbToHex($rgb, $normalize = FALSE) {
+    $out = 0;
+    foreach ($rgb as $k => $v) {
+      $out |= ((int) round($v * ($normalize ? 255 : 1)) << (16 - $k * 8));
+    }
+
+    return '#' . str_pad(dechex($out), 6, 0, STR_PAD_LEFT);
+  }
+
+  /**
+   * Converts a hex color into an RGB triplet.
+   *
+   * @param string $hex
+   *   The color in hex format.
+   * @param bool $normalize
+   *   If color should be normalized.
+   */
+  public function hexToRgb($hex, $normalize = FALSE) {
+    $hex = substr($hex, 1);
+    if (strlen($hex) == 3) {
+      $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
+    }
+    $c = hexdec($hex);
+    for ($i = 16; $i >= 0; $i -= 8) {
+      $out[] = (($c >> $i) & 0xFF) / ($normalize ? 255 : 1);
+    }
+
+    return $out;
+  }
+
+  /**
+   * Shifts a given color, using a reference pair and a target blend color.
+   *
+   * Note: this function is significantly different from the JS version, as it
+   * is written to match the blended images perfectly.
+   *
+   * Constraint: if (ref2 == target + (ref1 - target) * delta) for some fraction
+   * delta then (return == target + (given - target) * delta).
+   *
+   * Loose constraint: Preserve relative positions in saturation and luminance
+   * space.
+   *
+   * @param string $given
+   *   The given color.
+   * @param string $ref1
+   *   The reference pair.
+   * @param string $ref2
+   *   The reference pair.
+   * @param string $target
+   *   A target blend color.
+   */
+  private function shift($given, $ref1, $ref2, $target) {
+    // We assume that ref2 is a blend of ref1 and target and find
+    // delta based on the length of the difference vectors.
+    // Delta = 1 - |ref2 - ref1| / |white - ref1|.
+    $target = $this->hexToRgb($target, TRUE);
+    $ref1 = $this->hexToRgb($ref1, TRUE);
+    $ref2 = $this->hexToRgb($ref2, TRUE);
+    $numerator = 0;
+    $denominator = 0;
+    for ($i = 0; $i < 3; ++$i) {
+      $numerator += ($ref2[$i] - $ref1[$i]) * ($ref2[$i] - $ref1[$i]);
+      $denominator += ($target[$i] - $ref1[$i]) * ($target[$i] - $ref1[$i]);
+    }
+    $delta = ($denominator > 0) ? (1 - sqrt($numerator / $denominator)) : 0;
+
+    // Calculate the color that ref2 would be if the assumption was true.
+    for ($i = 0; $i < 3; ++$i) {
+      $ref3[$i] = $target[$i] + ($ref1[$i] - $target[$i]) * $delta;
+    }
+
+    // If the assumption is not true, there is a difference between ref2 and ref3.
+    // We measure this in HSL space. Notation: x' = hsl(x).
+    $ref2 = $this->rgbToHsl($ref2);
+    $ref3 = $this->rgbToHsl($ref3);
+    for ($i = 0; $i < 3; ++$i) {
+      $shift[$i] = $ref2[$i] - $ref3[$i];
+    }
+
+    // Take the given color, and blend it towards the target.
+    $given = $this->hexToRgb($given, TRUE);
+    for ($i = 0; $i < 3; ++$i) {
+      $result[$i] = $target[$i] + ($given[$i] - $target[$i]) * $delta;
+    }
+
+    // Finally, we apply the extra shift in HSL space.
+    // Note: if ref2 is a pure blend of ref1 and target, then |shift| = 0.
+    $result = $this->rgbToHsl($result);
+    for ($i = 0; $i < 3; ++$i) {
+      $result[$i] = min(1, max(0, $result[$i] + $shift[$i]));
+    }
+    $result = $this->hslToRgb($result);
+
+    // Return hex color.
+    return $this->rgbToHex($result, TRUE);
+  }
+
+  /**
+   * Converts an RGB triplet to HSL.
+   *
+   * @param array $rgb
+   *   Color to be processed.
+   */
+  private function rgbToHsl(array $rgb) {
+    $r = $rgb[0];
+    $g = $rgb[1];
+    $b = $rgb[2];
+    $min = min($r, min($g, $b));
+    $max = max($r, max($g, $b));
+    $delta = $max - $min;
+    $l = ($min + $max) / 2;
+    $s = 0;
+
+    if ($l > 0 && $l < 1) {
+      $s = $delta / ($l < 0.5 ? (2 * $l) : (2 - 2 * $l));
+    }
+
+    $h = 0;
+    if ($delta > 0) {
+      if ($max == $r && $max != $g) {
+        $h += ($g - $b) / $delta;
+      }
+      if ($max == $g && $max != $b) {
+        $h += (2 + ($b - $r) / $delta);
+      }
+      if ($max == $b && $max != $r) {
+        $h += (4 + ($r - $g) / $delta);
+      }
+      $h /= 6;
+    }
+
+    return [$h, $s, $l];
+  }
+
+  /**
+   * Converts an HSL triplet into RGB.
+   *
+   * @param array $hsl
+   *   HSL triplet.
+   */
+  private function hslToRgb(array $hsl) {
+    $h = $hsl[0];
+    $s = $hsl[1];
+    $l = $hsl[2];
+    $m2 = ($l <= 0.5) ? $l * ($s + 1) : $l + $s - $l * $s;
+    $m1 = $l * 2 - $m2;
+
+    return [
+      $this->hueToRgb($m1, $m2, $h + 0.33333),
+      $this->hueToRgb($m1, $m2, $h),
+      $this->hueToRgb($m1, $m2, $h - 0.33333),
+    ];
+  }
+
+  /**
+   * Helper function for ::hueToRgb().
+   *
+   * @param int $m1
+   *   The m1.
+   * @param int $m2
+   *   The m2.
+   * @param int $h
+   *   The hueToRgb.
+   */
+  private function hueToRgb($m1, $m2, $h) {
+    $h = ($h < 0) ? $h + 1 : (($h > 1) ? $h - 1 : $h);
+    if ($h * 6 < 1) {
+      return $m1 + ($m2 - $m1) * $h * 6;
+    }
+    if ($h * 2 < 1) {
+      return $m2;
+    }
+    if ($h * 3 < 2) {
+      return $m1 + ($m2 - $m1) * (0.66666 - $h) * 6;
+    }
+
+    return $m1;
+  }
+
+}
diff --git a/core/modules/color/tests/src/Functional/ColorTest.php b/core/modules/color/tests/src/Functional/ColorTest.php
index 7925f56..698ba72 100644
--- a/core/modules/color/tests/src/Functional/ColorTest.php
+++ b/core/modules/color/tests/src/Functional/ColorTest.php
@@ -90,9 +90,13 @@ protected function setUp(): void {
    * Tests the Color module functionality.
    */
   public function testColor() {
+    $theme_initializer = $this->container->get('theme.initialization');
+    $themeManager = $this->container->get('theme.manager');
     foreach ($this->themes as $theme => $test_values) {
+      $themeManager->setActiveTheme($theme_initializer->getActiveThemeByName($theme));
       $this->_testColor($theme, $test_values);
     }
+    $themeManager->setActiveTheme($theme_initializer->getActiveThemeByName($this->defaultTheme));
   }
 
   /**
@@ -109,6 +113,7 @@ public function _testColor($theme, $test_values) {
       ->set('default', $theme)
       ->save();
     $settings_path = 'admin/appearance/settings/' . $theme;
+    $colorThemDecorator = $this->container->get('color.theme_decorator');
 
     $this->drupalLogin($this->bigUser);
     $this->drupalGet($settings_path);
@@ -120,11 +125,11 @@ public function _testColor($theme, $test_values) {
     $this->submitForm($edit, 'Save configuration');
 
     $this->drupalGet('<front>');
-    $stylesheets = $this->config('color.theme.' . $theme)->get('stylesheets');
+    $themeFiles = $colorThemDecorator->getThemeFiles($theme);
     /** @var \Drupal\Core\File\FileUrlGeneratorInterface $file_url_generator */
     $file_url_generator = \Drupal::service('file_url_generator');
     // Make sure the color stylesheet is included in the content.
-    foreach ($stylesheets as $stylesheet) {
+    foreach ($themeFiles['css'] as $stylesheet) {
       $this->assertSession()->responseMatches('|' . $file_url_generator->generateString($stylesheet) . '|');
       $stylesheet_content = implode("\n", file($stylesheet));
       $this->assertStringContainsString('color: #123456', $stylesheet_content, 'Make sure the color we changed is in the color stylesheet. (' . $theme . ')');
@@ -137,8 +142,8 @@ public function _testColor($theme, $test_values) {
     $this->submitForm($edit, 'Save configuration');
 
     $this->drupalGet('<front>');
-    $stylesheets = $this->config('color.theme.' . $theme)->get('stylesheets');
-    foreach ($stylesheets as $stylesheet) {
+    $themeFiles = $colorThemDecorator->getThemeFiles($theme);
+    foreach ($themeFiles['css'] as $stylesheet) {
       $stylesheet_content = implode("\n", file($stylesheet));
       $this->assertStringContainsString('color: ' . $test_values['scheme_color'], $stylesheet_content, 'Make sure the color we changed is in the color stylesheet. (' . $theme . ')');
     }
@@ -210,14 +215,8 @@ public function testOverrideAndResetScheme() {
       ->set('default', 'bartik')
       ->save();
 
-    // Place branding block with site name and slogan into header region.
-    $this->drupalPlaceBlock('system_branding_block', ['region' => 'header']);
-
     $this->drupalGet('');
-    // Make sure the color logo is not being used.
-    $this->assertSession()->responseNotContains('files/color/bartik-');
-    // Make sure the original bartik logo exists.
-    $this->assertSession()->responseContains('bartik/logo.svg');
+    $this->assertSession()->responseNotContains('files/color');
 
     // Log in and set the color scheme to 'slate'.
     $this->drupalLogin($this->bigUser);
@@ -242,10 +241,7 @@ public function testOverrideAndResetScheme() {
     // Log out and ensure there is no color and we have the original logo.
     $this->drupalLogout();
     $this->drupalGet('');
-    // Make sure the color logo is not being used.
-    $this->assertSession()->responseNotContains('files/color/bartik-');
-    // Make sure the original bartik logo exists.
-    $this->assertSession()->responseContains('bartik/logo.svg');
+    $this->assertSession()->responseNotContains('files/color');
   }
 
 }
diff --git a/core/modules/color/tests/src/Kernel/Migrate/d7/MigrateColorTest.php b/core/modules/color/tests/src/Kernel/Migrate/d7/MigrateColorTest.php
index d33f2ab..0149294 100644
--- a/core/modules/color/tests/src/Kernel/Migrate/d7/MigrateColorTest.php
+++ b/core/modules/color/tests/src/Kernel/Migrate/d7/MigrateColorTest.php
@@ -39,12 +39,6 @@ protected function getFixtureFilePath() {
   public function testMigrateColor() {
     // Test Bartik migration.
     $config = $this->config('color.theme.bartik');
-    $files = [
-      'public://color/bartik-e0e23ad7/logo.png',
-      'public://color/bartik-e0e23ad7/colors.css',
-    ];
-    $this->assertSame($files, $config->get('files'));
-    $this->assertSame('public://color/bartik-e0e23ad7/logo.png', $config->get('logo'));
     $palette = [
       'top' => '#d0d0d0',
       'bottom' => '#c2c4c5',
@@ -57,7 +51,6 @@ public function testMigrateColor() {
       'link' => '#019dbf',
     ];
     $this->assertSame($palette, $config->get('palette'));
-    $this->assertSame(['public://color/bartik-e0e23ad7/colors.css'], $config->get('stylesheets'));
     // Test that the screenshot was not migrated.
     $this->assertNull($config->get('screenshot'));
 
