Remove the unnecessary `BuildConfigurationValue` wrapper around `BuildConfiguration`.

Instead, have `BuildConfiguration` implement `SkyValue` directly, and rename it to `BuildConfigurationValue`. Its `equals` and `hashCode` methods are removed - they were incomplete (notably, they did not consider the repository name). This was covered up by the fact that the wrapping `SkyValue` did not implement equality, preventing false change pruning.

`BuildConfigurationValue.Key` is promoted to a top-level class `BuildConfigurationKey`.

PiperOrigin-RevId: 406166220
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectCompletor.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectCompletor.java
index e189f45..4f13033 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectCompletor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectCompletor.java
@@ -20,6 +20,7 @@
 import com.google.devtools.build.lib.analysis.AspectValue;
 import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper.ArtifactsInOutputGroup;
 import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper.ArtifactsToBuild;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.bugreport.BugReporter;
 import com.google.devtools.build.lib.buildeventstream.BuildEventIdUtil;
 import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId;
@@ -92,8 +93,8 @@
   }
 
   @Nullable
-  private BuildEventId getConfigurationEventIdFromAspectKey(AspectKey aspectKey, Environment env)
-      throws InterruptedException {
+  private static BuildEventId getConfigurationEventIdFromAspectKey(
+      AspectKey aspectKey, Environment env) throws InterruptedException {
     if (aspectKey.getBaseConfiguredTargetKey().getConfigurationKey() == null) {
       return BuildEventIdUtil.nullConfigurationId();
     } else {
@@ -103,7 +104,7 @@
       if (buildConfigurationValue == null) {
         return null;
       }
-      return buildConfigurationValue.getConfiguration().getEventId();
+      return buildConfigurationValue.getEventId();
     }
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectCreationException.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectCreationException.java
index 89897d6..e70a0e1 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectCreationException.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectCreationException.java
@@ -13,7 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.skyframe;
 
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.ConfigurationId;
 import com.google.devtools.build.lib.causes.AnalysisFailedCause;
 import com.google.devtools.build.lib.causes.Cause;
@@ -29,7 +29,7 @@
 
 /** An exception indicating that there was a problem creating an aspect. */
 public final class AspectCreationException extends Exception implements SaneAnalysisException {
-  private static ConfigurationId toId(BuildConfiguration config) {
+  private static ConfigurationId toId(BuildConfigurationValue config) {
     return config == null ? null : config.getEventId().getConfiguration();
   }
 
@@ -48,7 +48,7 @@
   public AspectCreationException(
       String message,
       Label currentTarget,
-      @Nullable BuildConfiguration configuration,
+      @Nullable BuildConfigurationValue configuration,
       DetailedExitCode detailedExitCode) {
     this(
         message,
@@ -59,7 +59,7 @@
   }
 
   public AspectCreationException(
-      String message, Label currentTarget, @Nullable BuildConfiguration configuration) {
+      String message, Label currentTarget, @Nullable BuildConfigurationValue configuration) {
     this(
         message,
         currentTarget,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
index 2633d47..a8f56d5 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
@@ -41,7 +41,7 @@
 import com.google.devtools.build.lib.analysis.ResolvedToolchainContext;
 import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
 import com.google.devtools.build.lib.analysis.ToolchainCollection;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.analysis.config.ConfigConditions;
 import com.google.devtools.build.lib.analysis.config.ConfigurationResolver;
 import com.google.devtools.build.lib.analysis.config.DependencyEvaluationException;
@@ -235,7 +235,7 @@
     }
 
     ConfiguredTargetValue baseConfiguredTargetValue;
-    BuildConfiguration aspectConfiguration = null;
+    BuildConfigurationValue aspectConfiguration = null;
 
     try {
       baseConfiguredTargetValue =
@@ -248,9 +248,8 @@
     if (aspectHasConfiguration) {
       try {
         aspectConfiguration =
-            ((BuildConfigurationValue)
-                    baseAndAspectValues.get(key.getAspectConfigurationKey()).get())
-                .getConfiguration();
+            (BuildConfigurationValue)
+                baseAndAspectValues.get(key.getAspectConfigurationKey()).get();
       } catch (ConfiguredValueCreationException e) {
         throw new IllegalStateException("Unexpected exception from BuildConfigurationFunction when "
             + "computing " + key.getAspectConfigurationKey(), e);
@@ -260,7 +259,7 @@
     ConfiguredTarget associatedTarget = baseConfiguredTargetValue.getConfiguredTarget();
 
     Package targetPkg;
-    BuildConfiguration configuration = null;
+    BuildConfigurationValue configuration = null;
     PackageValue.Key packageKey =
         PackageValue.key(associatedTarget.getOriginalLabel().getPackageIdentifier());
     if (associatedTarget.getConfigurationKey() == null) {
@@ -280,9 +279,7 @@
         return null;
       }
       targetPkg = ((PackageValue) result.get(packageKey)).getPackage();
-      configuration =
-          ((BuildConfigurationValue) result.get(associatedTarget.getConfigurationKey()))
-              .getConfiguration();
+      configuration = (BuildConfigurationValue) result.get(associatedTarget.getConfigurationKey());
     }
 
     Target target;
@@ -518,7 +515,10 @@
 
   @Nullable
   private static UnloadedToolchainContext getUnloadedToolchainContext(
-      Environment env, AspectKey key, Aspect aspect, @Nullable BuildConfiguration configuration)
+      Environment env,
+      AspectKey key,
+      Aspect aspect,
+      @Nullable BuildConfigurationValue configuration)
       throws InterruptedException, AspectCreationException {
     // Determine what toolchains are needed by this target.
     UnloadedToolchainContext unloadedToolchainContext = null;
@@ -531,7 +531,7 @@
             (UnloadedToolchainContext)
                 env.getValueOrThrow(
                     ToolchainContextKey.key()
-                        .configurationKey(BuildConfigurationValue.key(configuration))
+                        .configurationKey(configuration.getKey())
                         .requiredToolchainTypeLabels(requiredToolchains)
                         .build(),
                     ToolchainException.class);
@@ -553,7 +553,7 @@
    */
   // TODO(#10523): Remove this when the migration period for toolchain transitions has ended.
   private static boolean shouldUseToolchainTransition(
-      @Nullable BuildConfiguration configuration, AspectDefinition definition) {
+      @Nullable BuildConfigurationValue configuration, AspectDefinition definition) {
     // Check whether the global incompatible change flag is set.
     if (configuration != null) {
       PlatformOptions platformOptions = configuration.getOptions().get(PlatformOptions.class);
@@ -624,11 +624,11 @@
   @Nullable
   private AspectValue createAliasAspect(
       Environment env,
-      BuildConfiguration hostConfiguration,
+      BuildConfigurationValue hostConfiguration,
       TargetAndConfiguration originalTarget,
       Aspect aspect,
       AspectKey originalKey,
-      BuildConfiguration aspectConfiguration,
+      BuildConfigurationValue aspectConfiguration,
       ConfiguredTarget configuredTarget)
       throws AspectFunctionException, InterruptedException {
     ImmutableList<Label> aliasChain =
@@ -827,7 +827,7 @@
       Aspect aspect,
       ConfiguredAspectFactory aspectFactory,
       ConfiguredTargetAndData associatedTarget,
-      BuildConfiguration aspectConfiguration,
+      BuildConfigurationValue aspectConfiguration,
       ConfigConditions configConditions,
       ResolvedToolchainContext toolchainContext,
       OrderedSetMultimap<DependencyKind, ConfiguredTargetAndData> directDeps,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectKeyCreator.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectKeyCreator.java
index 10ba833..0d4c5ac 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectKeyCreator.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectKeyCreator.java
@@ -17,7 +17,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Interner;
 import com.google.devtools.build.lib.actions.ActionLookupKey;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.BlazeInterners;
 import com.google.devtools.build.lib.packages.AspectClass;
@@ -38,21 +38,21 @@
 
   public static AspectKey createAspectKey(
       Label label,
-      @Nullable BuildConfiguration baseConfiguration,
+      @Nullable BuildConfigurationValue baseConfiguration,
       ImmutableList<AspectKey> baseKeys,
       AspectDescriptor aspectDescriptor,
-      @Nullable BuildConfiguration aspectConfiguration) {
+      @Nullable BuildConfigurationValue aspectConfiguration) {
     return AspectKey.createAspectKey(
         ConfiguredTargetKey.builder().setLabel(label).setConfiguration(baseConfiguration).build(),
         baseKeys,
         aspectDescriptor,
-        aspectConfiguration == null ? null : BuildConfigurationValue.key(aspectConfiguration));
+        aspectConfiguration == null ? null : aspectConfiguration.getKey());
   }
 
   public static AspectKey createAspectKey(
       AspectDescriptor aspectDescriptor,
       ImmutableList<AspectKey> baseKeys,
-      BuildConfigurationValue.Key aspectConfigurationKey,
+      BuildConfigurationKey aspectConfigurationKey,
       ConfiguredTargetKey baseConfiguredTargetKey) {
     return AspectKey.createAspectKey(
         baseConfiguredTargetKey, baseKeys, aspectDescriptor, aspectConfigurationKey);
@@ -60,20 +60,20 @@
 
   public static AspectKey createAspectKey(
       Label label,
-      @Nullable BuildConfiguration baseConfiguration,
+      @Nullable BuildConfigurationValue baseConfiguration,
       AspectDescriptor aspectDescriptor,
-      @Nullable BuildConfiguration aspectConfiguration) {
+      @Nullable BuildConfigurationValue aspectConfiguration) {
     return AspectKey.createAspectKey(
         ConfiguredTargetKey.builder().setLabel(label).setConfiguration(baseConfiguration).build(),
         ImmutableList.of(),
         aspectDescriptor,
-        aspectConfiguration == null ? null : BuildConfigurationValue.key(aspectConfiguration));
+        aspectConfiguration == null ? null : aspectConfiguration.getKey());
   }
 
   public static TopLevelAspectsKey createTopLevelAspectsKey(
       ImmutableList<AspectClass> topLevelAspectsClasses,
       Label targetLabel,
-      @Nullable BuildConfiguration configuration) {
+      @Nullable BuildConfigurationValue configuration) {
     return TopLevelAspectsKey.createInternal(
         topLevelAspectsClasses,
         targetLabel,
@@ -110,14 +110,14 @@
   @AutoCodec
   public static final class AspectKey extends AspectBaseKey {
     private final ImmutableList<AspectKey> baseKeys;
-    @Nullable private final BuildConfigurationValue.Key aspectConfigurationKey;
+    @Nullable private final BuildConfigurationKey aspectConfigurationKey;
     private final AspectDescriptor aspectDescriptor;
 
     private AspectKey(
         ConfiguredTargetKey baseConfiguredTargetKey,
         ImmutableList<AspectKey> baseKeys,
         AspectDescriptor aspectDescriptor,
-        @Nullable BuildConfigurationValue.Key aspectConfigurationKey,
+        @Nullable BuildConfigurationKey aspectConfigurationKey,
         int hashCode) {
       super(baseConfiguredTargetKey, hashCode);
       this.baseKeys = baseKeys;
@@ -131,7 +131,7 @@
         ConfiguredTargetKey baseConfiguredTargetKey,
         ImmutableList<AspectKey> baseKeys,
         AspectDescriptor aspectDescriptor,
-        @Nullable BuildConfigurationValue.Key aspectConfigurationKey) {
+        @Nullable BuildConfigurationKey aspectConfigurationKey) {
       return aspectKeyInterner.intern(
           new AspectKey(
               baseConfiguredTargetKey,
@@ -207,7 +207,7 @@
      * base target's configuration.
      */
     @Nullable
-    public BuildConfigurationValue.Key getAspectConfigurationKey() {
+    public BuildConfigurationKey getAspectConfigurationKey() {
       return aspectConfigurationKey;
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
index 78f260b..4f2693f 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
@@ -109,7 +109,7 @@
         ":artifact_nested_set_key",
         ":aspect_creation_exception",
         ":aspect_key_creator",
-        ":build_configuration_value",
+        ":build_configuration",
         ":build_driver_key",
         ":build_driver_value",
         ":build_info_collection_value",
@@ -815,7 +815,7 @@
     name = "aspect_key_creator",
     srcs = ["AspectKeyCreator.java"],
     deps = [
-        ":build_configuration_value",
+        ":build_configuration",
         ":configured_target_key",
         ":sky_functions",
         "//src/main/java/com/google/devtools/build/lib/actions:action_lookup_key",
@@ -900,14 +900,13 @@
 )
 
 java_library(
-    name = "build_configuration_value",
+    name = "build_configuration",
     srcs = [
-        "BuildConfigurationValue.java",
+        "BuildConfigurationKey.java",
         "PlatformMappingValue.java",
     ],
     deps = [
         ":sky_functions",
-        "//src/main/java/com/google/devtools/build/lib/analysis:config/build_configuration",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/build_options",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/fragment_class_set",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/fragment_options",
@@ -928,7 +927,7 @@
     name = "build_info_collection_value",
     srcs = ["BuildInfoCollectionValue.java"],
     deps = [
-        ":build_configuration_value",
+        ":build_configuration",
         ":sky_functions",
         "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/actions:action_lookup_key",
@@ -1140,7 +1139,7 @@
     name = "configured_target_and_data",
     srcs = ["ConfiguredTargetAndData.java"],
     deps = [
-        ":build_configuration_value",
+        ":build_configuration",
         ":package_value",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/build_configuration",
         "//src/main/java/com/google/devtools/build/lib/analysis:configured_target",
@@ -1156,7 +1155,7 @@
     name = "configured_target_key",
     srcs = ["ConfiguredTargetKey.java"],
     deps = [
-        ":build_configuration_value",
+        ":build_configuration",
         ":sky_functions",
         ":toolchain_context_key",
         "//src/main/java/com/google/devtools/build/lib/actions:action_lookup_key",
@@ -2511,7 +2510,7 @@
     name = "toolchain_context_key",
     srcs = ["ToolchainContextKey.java"],
     deps = [
-        ":build_configuration_value",
+        ":build_configuration",
         ":sky_functions",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/skyframe:skyframe-objects",
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationFunction.java
index 005646f..821ca32 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationFunction.java
@@ -21,7 +21,7 @@
 import com.google.devtools.build.lib.actions.ActionEnvironment;
 import com.google.devtools.build.lib.analysis.BlazeDirectories;
 import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
 import com.google.devtools.build.lib.analysis.config.CoreOptions;
 import com.google.devtools.build.lib.analysis.config.Fragment;
@@ -67,7 +67,7 @@
       return null;
     }
 
-    BuildConfigurationValue.Key key = (BuildConfigurationValue.Key) skyKey.argument();
+    BuildConfigurationKey key = (BuildConfigurationKey) skyKey.argument();
     ImmutableSortedMap<Class<? extends Fragment>, Fragment> fragments;
     try {
       fragments = getConfigurationFragments(key);
@@ -91,23 +91,21 @@
 
     try {
       return new BuildConfigurationValue(
-          new BuildConfiguration(
-              directories,
-              fragments,
-              fragmentClasses,
-              key.getOptions(),
-              ruleClassProvider.getReservedActionMnemonics(),
-              actionEnvironment,
-              RepositoryName.createFromValidStrippedName(workspaceNameValue.getName()),
-              starlarkSemantics.getBool(
-                  BuildLanguageOptions.EXPERIMENTAL_SIBLING_REPOSITORY_LAYOUT)));
+          directories,
+          fragments,
+          fragmentClasses,
+          key.getOptions(),
+          ruleClassProvider.getReservedActionMnemonics(),
+          actionEnvironment,
+          RepositoryName.createFromValidStrippedName(workspaceNameValue.getName()),
+          starlarkSemantics.getBool(BuildLanguageOptions.EXPERIMENTAL_SIBLING_REPOSITORY_LAYOUT));
     } catch (InvalidMnemonicException e) {
       throw new BuildConfigurationFunctionException(e);
     }
   }
 
   private ImmutableSortedMap<Class<? extends Fragment>, Fragment> getConfigurationFragments(
-      BuildConfigurationValue.Key key) throws InvalidConfigurationException {
+      BuildConfigurationKey key) throws InvalidConfigurationException {
     FragmentClassSet fragmentClasses = key.getFragments();
     ImmutableSortedMap.Builder<Class<? extends Fragment>, Fragment> fragments =
         ImmutableSortedMap.orderedBy(FragmentClassSet.LEXICAL_FRAGMENT_SORTER);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationKey.java b/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationKey.java
new file mode 100644
index 0000000..2a9b7ea
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationKey.java
@@ -0,0 +1,143 @@
+// Copyright 2021 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.skyframe;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Interner;
+import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.FragmentClassSet;
+import com.google.devtools.build.lib.concurrent.BlazeInterners;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
+import com.google.devtools.build.skyframe.SkyFunctionName;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.common.options.OptionsParsingException;
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * {@link SkyKey} for {@link com.google.devtools.build.lib.analysis.config.BuildConfigurationValue}.
+ */
+@AutoCodec
+public final class BuildConfigurationKey implements SkyKey, Serializable {
+
+  /**
+   * Creates a new configuration key based on the given options, after applying a platform mapping
+   * transformation.
+   *
+   * @param platformMappingValue sky value that can transform a configuration key based on a
+   *     platform mapping
+   * @param fragments set of options fragments this configuration should cover
+   * @param options the desired configuration
+   * @throws OptionsParsingException if the platform mapping cannot be parsed
+   */
+  public static BuildConfigurationKey withPlatformMapping(
+      PlatformMappingValue platformMappingValue, FragmentClassSet fragments, BuildOptions options)
+      throws OptionsParsingException {
+    return platformMappingValue.map(withoutPlatformMapping(fragments, options));
+  }
+
+  /**
+   * Returns the key for a requested configuration.
+   *
+   * <p>Callers are responsible for applying the platform mapping or ascertaining that a platform
+   * mapping is not required.
+   *
+   * @param fragments the fragments the configuration should contain
+   * @param options the {@link BuildOptions} object the {@link BuildOptions} should be rebuilt from
+   */
+  @AutoCodec.Instantiator
+  public static BuildConfigurationKey withoutPlatformMapping(
+      FragmentClassSet fragments, BuildOptions options) {
+    return interner.intern(new BuildConfigurationKey(fragments, options));
+  }
+
+  private static final Interner<BuildConfigurationKey> interner = BlazeInterners.newWeakInterner();
+
+  private final FragmentClassSet fragments;
+  private final BuildOptions options;
+  private final int hashCode;
+
+  private BuildConfigurationKey(FragmentClassSet fragments, BuildOptions options) {
+    this.fragments = Preconditions.checkNotNull(fragments);
+    this.options = Preconditions.checkNotNull(options);
+    this.hashCode = Objects.hash(fragments, options);
+  }
+
+  public FragmentClassSet getFragments() {
+    return fragments;
+  }
+
+  public BuildOptions getOptions() {
+    return options;
+  }
+
+  @Override
+  public SkyFunctionName functionName() {
+    return SkyFunctions.BUILD_CONFIGURATION;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (!(o instanceof BuildConfigurationKey)) {
+      return false;
+    }
+    BuildConfigurationKey otherConfig = (BuildConfigurationKey) o;
+    return options.equals(otherConfig.options) && fragments.equals(otherConfig.fragments);
+  }
+
+  @Override
+  public int hashCode() {
+    return hashCode;
+  }
+
+  @Override
+  public String toString() {
+    // This format is depended on by integration tests.
+    // TODO(blaze-configurability-team): This should at least include the length of fragments.
+    // to at least remind devs that this Key has TWO key parts.
+    return "BuildConfigurationKey[" + options.checksum() + "]";
+  }
+
+  /**
+   * Returns a string representation that can be safely used for comparison purposes.
+   *
+   * <p>Unlike toString, which is short and good for printing in debug contexts, this is long
+   * because it includes sufficient information in options and fragments. toString alone is
+   * insufficient because multiple Keys can have the same options checksum (and thus same toString)
+   * but different fragments.
+   *
+   * <p>This function is meant to address two potential, trimming-related scenarios: 1. If trimming
+   * by only trimming BuildOptions (e.g. --trim_test_configuration), then after the initial
+   * trimming, fragments has extra classes (corresponding to those trimmed). Notably, dependencies
+   * of trimmed targets will create Keys with a properly trimmed set of fragments. Thus, will easily
+   * have two Keys with the same (trimmed) BuildOptions but different fragments yet corresponding to
+   * the same (trimmed) BuildConfigurationValue.
+   *
+   * <p>2. If trimming by only trimming fragments (at time of this comment, unsure whether this is
+   * ever done in active code), then BuildOptions has extra classes. The returned
+   * BuildConfigurationValue is properly trimmed (with the extra classes BuildOptions removed)
+   * although notably with a different checksum compared to the Key checksum. Note that given a
+   * target that is doing trimming like this, the reverse dependency of the target (i.e. without
+   * trimming) could easily involve a Key with the same (untrimmed!) BuildOptions but different
+   * fragments. However, unlike in case 1, they will correspond to different
+   * BuildConfigurationValue.
+   */
+  public String toComparableString() {
+    return "BuildConfigurationKey[" + options.checksum() + ", " + fragments + "]";
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationValue.java
deleted file mode 100644
index ef3588c..0000000
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationValue.java
+++ /dev/null
@@ -1,180 +0,0 @@
-// Copyright 2015 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package com.google.devtools.build.lib.skyframe;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Interner;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
-import com.google.devtools.build.lib.analysis.config.BuildOptions;
-import com.google.devtools.build.lib.analysis.config.FragmentClassSet;
-import com.google.devtools.build.lib.concurrent.BlazeInterners;
-import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
-import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
-import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
-import com.google.devtools.build.skyframe.SkyFunctionName;
-import com.google.devtools.build.skyframe.SkyKey;
-import com.google.devtools.build.skyframe.SkyValue;
-import com.google.devtools.common.options.OptionsParsingException;
-import java.io.Serializable;
-import java.util.Objects;
-
-/** A Skyframe value representing a {@link BuildConfiguration}. */
-// TODO(bazel-team): mark this immutable when BuildConfiguration is immutable.
-// @Immutable
-@AutoCodec
-@ThreadSafe
-public class BuildConfigurationValue implements SkyValue {
-  private final BuildConfiguration configuration;
-
-  BuildConfigurationValue(BuildConfiguration configuration) {
-    this.configuration = configuration;
-  }
-
-  public BuildConfiguration getConfiguration() {
-    return configuration;
-  }
-
-  /**
-   * Creates a new configuration key based on the given options, after applying a platform mapping
-   * transformation.
-   *
-   * @param platformMappingValue sky value that can transform a configuration key based on a
-   *     platform mapping
-   * @param fragments set of options fragments this configuration should cover
-   * @param options the desired configuration
-   * @throws OptionsParsingException if the platform mapping cannot be parsed
-   */
-  public static Key keyWithPlatformMapping(
-      PlatformMappingValue platformMappingValue,
-      FragmentClassSet fragments,
-      BuildOptions options)
-      throws OptionsParsingException {
-    return platformMappingValue.map(keyWithoutPlatformMapping(fragments, options));
-  }
-
-  /**
-   * Returns the key for a requested configuration.
-   *
-   * <p>Callers are responsible for applying the platform mapping or ascertaining that a platform
-   * mapping is not required.
-   *
-   * @param fragments the fragments the configuration should contain
-   * @param options the {@link BuildOptions} object the {@link BuildOptions} should be rebuilt from
-   */
-  public static Key keyWithoutPlatformMapping(FragmentClassSet fragments, BuildOptions options) {
-    return Key.create(fragments, options);
-  }
-
-  /**
-   * Returns a configuration key for the given configuration.
-   *
-   * <p>Note that this key creation method does not apply a platform mapping, it is assumed that the
-   * passed configuration was created with one such and thus its key does not need to be mapped
-   * again.
-   *
-   * @param buildConfiguration configuration whose key is requested
-   */
-  public static Key key(BuildConfiguration buildConfiguration) {
-    return keyWithoutPlatformMapping(
-        buildConfiguration.fragmentClasses(), buildConfiguration.getOptions());
-  }
-
-  /** {@link SkyKey} for {@link BuildConfigurationValue}. */
-  @AutoCodec
-  public static final class Key implements SkyKey, Serializable {
-    private static final Interner<Key> keyInterner = BlazeInterners.newWeakInterner();
-
-    private final FragmentClassSet fragments;
-    private final BuildOptions options;
-    private final int hashCode;
-
-    @AutoCodec.Instantiator
-    @VisibleForSerialization
-    static Key create(FragmentClassSet fragments, BuildOptions options) {
-      return keyInterner.intern(new Key(fragments, options));
-    }
-
-    private Key(FragmentClassSet fragments, BuildOptions options) {
-      this.fragments = Preconditions.checkNotNull(fragments);
-      this.options = Preconditions.checkNotNull(options);
-      this.hashCode = Objects.hash(fragments, options);
-    }
-
-    public FragmentClassSet getFragments() {
-      return fragments;
-    }
-
-    public BuildOptions getOptions() {
-      return options;
-    }
-
-    @Override
-    public SkyFunctionName functionName() {
-      return SkyFunctions.BUILD_CONFIGURATION;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) {
-        return true;
-      }
-      if (!(o instanceof Key)) {
-        return false;
-      }
-      Key otherConfig = (Key) o;
-      return options.equals(otherConfig.options) && fragments.equals(otherConfig.fragments);
-    }
-
-    @Override
-    public int hashCode() {
-      return hashCode;
-    }
-
-    @Override
-    public String toString() {
-      // This format is depended on by integration tests.
-      // TODO(blaze-configurability-team): This should at least include the length of fragments.
-      // to at least remind devs that this Key has TWO key parts.
-      return "BuildConfigurationValue.Key[" + options.checksum() + "]";
-    }
-
-    /**
-     * Return a string representation that can be safely used for comparison purposes.
-     *
-     * <p>Unlike toString, which is short and good for printing in debug contexts, this is long
-     * because it includes sufficient information in options and fragments. toString alone is
-     * insufficient because multiple Keys can have the same options checksum (and thus same
-     * toString) but different fragments.
-     *
-     * <p>This function is meant to address two potential, trimming-related scenarios: 1. If
-     * trimming by only trimming BuildOptions (e.g. --trim_test_configuration), then after the
-     * initial trimming, fragments has extra classes (corresponding to those trimmed). Notably,
-     * dependencies of trimmed targets will create Keys with a properly trimmed set of fragments.
-     * Thus, will easily have two Keys with the same (trimmed) BuildOptions but different fragments
-     * yet corresponding to the same (trimmed) BuildConfigurationValue.
-     *
-     * <p>2. If trimming by only trimming fragments (at time of this comment, unsure whether this is
-     * ever done in active code), then BuildOptions has extra classes. The returned
-     * BuildConfigurationValue is properly trimmed (with the extra classes BuildOptions removed)
-     * although notably with a different checksum compared to the Key checksum. Note that given a
-     * target that is doing trimming like this, the reverse dependency of the target (i.e. without
-     * trimming) could easily involve a Key with the same (untrimmed!) BuildOptions but different
-     * fragments. However, unlike in case 1, they will correspond to different
-     * BuildConfigurationValue.
-     */
-    public String toComparableString() {
-      return "BuildConfigurationValue.Key[" + options.checksum() + ", " + fragments + "]";
-    }
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BuildInfoCollectionFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/BuildInfoCollectionFunction.java
index dda34ba..bf97a1f 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BuildInfoCollectionFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BuildInfoCollectionFunction.java
@@ -25,7 +25,7 @@
 import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory.BuildInfoContext;
 import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory.BuildInfoType;
 import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoKey;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.skyframe.BuildInfoCollectionValue.BuildInfoKeyAndConfig;
 import com.google.devtools.build.lib.skyframe.PrecomputedValue.Precomputed;
 import com.google.devtools.build.skyframe.SkyFunction;
@@ -65,8 +65,8 @@
     WorkspaceStatusValue infoArtifactValue =
         (WorkspaceStatusValue) result.get(WorkspaceStatusValue.BUILD_INFO_KEY);
 
-    BuildConfiguration config =
-        ((BuildConfigurationValue) result.get(keyAndConfig.getConfigKey())).getConfiguration();
+    BuildConfigurationValue config =
+        (BuildConfigurationValue) result.get(keyAndConfig.getConfigKey());
     Map<BuildInfoKey, BuildInfoFactory> buildInfoFactories = BUILD_INFO_FACTORIES.get(env);
     BuildInfoFactory buildInfoFactory = buildInfoFactories.get(keyAndConfig.getInfoKey());
     Preconditions.checkState(buildInfoFactory.isEnabled(config));
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BuildInfoCollectionValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/BuildInfoCollectionValue.java
index 79588e2..76dc915 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BuildInfoCollectionValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BuildInfoCollectionValue.java
@@ -20,7 +20,7 @@
 import com.google.devtools.build.lib.actions.BasicActionLookupValue;
 import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoCollection;
 import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoKey;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.BlazeInterners;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
@@ -50,9 +50,9 @@
     return getStringHelper().add("collection", collection).toString();
   }
 
-  public static BuildInfoKeyAndConfig key(BuildInfoKey key, @Nullable BuildConfiguration config) {
-    return BuildInfoKeyAndConfig.create(
-        key, config == null ? null : BuildConfigurationValue.key(config));
+  public static BuildInfoKeyAndConfig key(
+      BuildInfoKey key, @Nullable BuildConfigurationValue config) {
+    return BuildInfoKeyAndConfig.create(key, config == null ? null : config.getKey());
   }
 
   /** Key for BuildInfoCollectionValues. */
@@ -62,16 +62,15 @@
         BlazeInterners.newWeakInterner();
 
     private final BuildInfoKey infoKey;
-    private final BuildConfigurationValue.Key configKey;
+    private final BuildConfigurationKey configKey;
 
-    private BuildInfoKeyAndConfig(BuildInfoKey key, BuildConfigurationValue.Key configKey) {
+    private BuildInfoKeyAndConfig(BuildInfoKey key, BuildConfigurationKey configKey) {
       this.infoKey = Preconditions.checkNotNull(key, configKey);
       this.configKey = Preconditions.checkNotNull(configKey, key);
     }
 
     @AutoCodec.Instantiator
-    static BuildInfoKeyAndConfig create(
-        BuildInfoKey infoKey, BuildConfigurationValue.Key configKey) {
+    static BuildInfoKeyAndConfig create(BuildInfoKey infoKey, BuildConfigurationKey configKey) {
       return keyInterner.intern(new BuildInfoKeyAndConfig(infoKey, configKey));
     }
 
@@ -84,7 +83,7 @@
       return infoKey;
     }
 
-    BuildConfigurationValue.Key getConfigKey() {
+    BuildConfigurationKey getConfigKey() {
       return configKey;
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetAndData.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetAndData.java
index 1d06228..00fef49 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetAndData.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetAndData.java
@@ -19,7 +19,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.skyframe.SkyFunction;
@@ -30,25 +30,26 @@
 
 /**
  * A container class for a {@link ConfiguredTarget} and associated data, {@link Target}, {@link
- * BuildConfiguration}, and transition keys. In the future, {@link ConfiguredTarget} objects will no
- * longer contain their associated {@link BuildConfiguration}. Consumers that need the {@link
- * Target} or {@link BuildConfiguration} must therefore have access to one of these objects.
+ * BuildConfigurationValue}, and transition keys. In the future, {@link ConfiguredTarget} objects
+ * will no longer contain their associated {@link BuildConfigurationValue}. Consumers that need the
+ * {@link Target} or {@link BuildConfigurationValue} must therefore have access to one of these
+ * objects.
  *
  * <p>These objects are intended to be short-lived, never stored in Skyframe, since they pair three
  * heavyweight objects, a {@link ConfiguredTarget}, a {@link Target} (which holds a {@link
- * com.google.devtools.build.lib.packages.Package}), and a {@link BuildConfiguration}.
+ * com.google.devtools.build.lib.packages.Package}), and a {@link BuildConfigurationValue}.
  */
 public class ConfiguredTargetAndData {
   private final ConfiguredTarget configuredTarget;
   private final Target target;
-  private final BuildConfiguration configuration;
+  private final BuildConfigurationValue configuration;
   private final ImmutableList<String> transitionKeys;
 
   @VisibleForTesting
   public ConfiguredTargetAndData(
       ConfiguredTarget configuredTarget,
       Target target,
-      BuildConfiguration configuration,
+      BuildConfigurationValue configuration,
       ImmutableList<String> transitionKeys) {
     this.configuredTarget = configuredTarget;
     this.target = target;
@@ -60,7 +61,7 @@
             + " ConfiguredTarget's label %s is not equal to Target's label %s",
         configuredTarget.getLabel(),
         target.getLabel());
-    BuildConfigurationValue.Key innerConfigurationKey = configuredTarget.getConfigurationKey();
+    BuildConfigurationKey innerConfigurationKey = configuredTarget.getConfigurationKey();
     if (configuration == null) {
       Preconditions.checkState(
           innerConfigurationKey == null,
@@ -68,7 +69,7 @@
           configuredTarget,
           target);
     } else {
-      BuildConfigurationValue.Key configurationKey = BuildConfigurationValue.key(configuration);
+      BuildConfigurationKey configurationKey = configuration.getKey();
       Preconditions.checkState(
           innerConfigurationKey.equals(configurationKey),
           "Configurations don't match: %s %s %s (%s %s)",
@@ -83,10 +84,10 @@
   @Nullable
   static ConfiguredTargetAndData fromConfiguredTargetInSkyframe(
       ConfiguredTarget ct, SkyFunction.Environment env) throws InterruptedException {
-    BuildConfiguration configuration = null;
+    BuildConfigurationValue configuration = null;
     ImmutableSet<SkyKey> packageAndMaybeConfiguration;
     PackageValue.Key packageKey = PackageValue.key(ct.getLabel().getPackageIdentifier());
-    BuildConfigurationValue.Key configurationKeyMaybe = ct.getConfigurationKey();
+    BuildConfigurationKey configurationKeyMaybe = ct.getConfigurationKey();
     if (configurationKeyMaybe == null) {
       packageAndMaybeConfiguration = ImmutableSet.of(packageKey);
     } else {
@@ -100,12 +101,11 @@
       return null;
     }
     if (configurationKeyMaybe != null) {
-      BuildConfigurationValue buildConfigurationValue =
+      configuration =
           (BuildConfigurationValue) packageAndMaybeConfigurationValues.get(configurationKeyMaybe);
-      if (buildConfigurationValue == null) {
+      if (configuration == null) {
         return null;
       }
-      configuration = buildConfigurationValue.getConfiguration();
     }
     try {
       return new ConfiguredTargetAndData(
@@ -130,7 +130,7 @@
     return target;
   }
 
-  public BuildConfiguration getConfiguration() {
+  public BuildConfigurationValue getConfiguration() {
     return configuration;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
index 7bdd7a7..4ee1e37 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
@@ -45,7 +45,7 @@
 import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
 import com.google.devtools.build.lib.analysis.ToolchainCollection;
 import com.google.devtools.build.lib.analysis.ToolchainContext;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
 import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
 import com.google.devtools.build.lib.analysis.config.ConfigConditions;
@@ -199,7 +199,7 @@
 
     ConfiguredTargetKey configuredTargetKey = (ConfiguredTargetKey) key.argument();
     Label label = configuredTargetKey.getLabel();
-    BuildConfiguration configuration = null;
+    BuildConfigurationValue configuration = null;
     ImmutableSet<SkyKey> packageAndMaybeConfiguration;
     SkyKey packageKey = PackageValue.key(label.getPackageIdentifier());
     SkyKey configurationKeyMaybe = configuredTargetKey.getConfigurationKey();
@@ -216,8 +216,7 @@
     PackageValue packageValue = (PackageValue) packageAndMaybeConfigurationValues.get(packageKey);
     if (configurationKeyMaybe != null) {
       configuration =
-          ((BuildConfigurationValue) packageAndMaybeConfigurationValues.get(configurationKeyMaybe))
-              .getConfiguration();
+          (BuildConfigurationValue) packageAndMaybeConfigurationValues.get(configurationKeyMaybe);
     }
 
     // TODO(ulfjack): This tries to match the logic in TransitiveTargetFunction /
@@ -470,7 +469,7 @@
       return new ComputedToolchainContexts();
     }
     Rule rule = ((Rule) targetAndConfig.getTarget());
-    BuildConfiguration configuration = targetAndConfig.getConfiguration();
+    BuildConfigurationValue configuration = targetAndConfig.getConfiguration();
 
     ImmutableSet<Label> requiredDefaultToolchains =
         rule.getRuleClassObject().getRequiredToolchains();
@@ -522,8 +521,8 @@
                 toolchainTaggedTrimmingTransition.requiresOptionFragments()),
             env.getListener());
 
-    BuildConfigurationValue.Key toolchainConfig =
-        BuildConfigurationValue.keyWithoutPlatformMapping(
+    BuildConfigurationKey toolchainConfig =
+        BuildConfigurationKey.withoutPlatformMapping(
             configuration.fragmentClasses(), toolchainOptions);
 
     Map<String, ToolchainContextKey> toolchainContextKeys = new HashMap<>();
@@ -639,14 +638,14 @@
       @Nullable ToolchainCollection<ToolchainContext> toolchainContexts,
       boolean useToolchainTransition,
       RuleClassProvider ruleClassProvider,
-      BuildConfiguration hostConfiguration,
+      BuildConfigurationValue hostConfiguration,
       @Nullable NestedSetBuilder<Package> transitivePackagesForPackageRootResolution,
       NestedSetBuilder<Cause> transitiveRootCauses)
       throws DependencyEvaluationException, ConfiguredValueCreationException,
           AspectCreationException, InterruptedException {
     // Create the map from attributes to set of (target, transition) pairs.
     OrderedSetMultimap<DependencyKind, DependencyKey> initialDependencies;
-    BuildConfiguration configuration = ctgValue.getConfiguration();
+    BuildConfigurationValue configuration = ctgValue.getConfiguration();
     Label label = ctgValue.getLabel();
     try {
       initialDependencies =
@@ -891,12 +890,10 @@
               }
             }
             try {
-              BuildConfiguration depConfiguration = dep.getConfiguration();
-              BuildConfigurationValue.Key depKey =
-                  depValue.getConfiguredTarget().getConfigurationKey();
-              if (depKey != null && !depKey.equals(BuildConfigurationValue.key(depConfiguration))) {
-                depConfiguration =
-                    ((BuildConfigurationValue) env.getValue(depKey)).getConfiguration();
+              BuildConfigurationValue depConfiguration = dep.getConfiguration();
+              BuildConfigurationKey depKey = depValue.getConfiguredTarget().getConfigurationKey();
+              if (depKey != null && !depKey.equals(depConfiguration.getKey())) {
+                depConfiguration = (BuildConfigurationValue) env.getValue(depKey);
               }
               result.put(
                   key,
@@ -959,7 +956,7 @@
       @Nullable NestedSetBuilder<Package> transitivePackagesForPackageRootResolution)
       throws ConfiguredValueCreationException, InterruptedException {
     Target target = ctgValue.getTarget();
-    BuildConfiguration configuration = ctgValue.getConfiguration();
+    BuildConfigurationValue configuration = ctgValue.getConfiguration();
 
     // Should be successfully evaluated and cached from the loading phase.
     StarlarkBuiltinsValue starlarkBuiltinsValue =
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetKey.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetKey.java
index 0457e20..58d7587 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetKey.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetKey.java
@@ -20,7 +20,7 @@
 import com.google.common.collect.Interner;
 import com.google.devtools.build.lib.actions.ActionLookupKey;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.BlazeInterners;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
@@ -29,34 +29,34 @@
 import javax.annotation.Nullable;
 
 /**
- * In simple form, a ({@link Label}, {@link BuildConfiguration}) pair used to trigger immediate
+ * In simple form, a ({@link Label}, {@link BuildConfigurationValue}) pair used to trigger immediate
  * dependency resolution and the rule analysis.
  *
- * <p>In practice, a ({@link Label}, canonical and post-transition {@link
- * BuildConfigurationValue.Key}) pair plus a possible execution platform override {@link Label} with
- * special constraints. To elaborate, in order of highest to lowest potential for concern:
+ * <p>In practice, a ({@link Label}, canonical and post-transition {@link BuildConfigurationKey})
+ * pair plus a possible execution platform override {@link Label} with special constraints. To
+ * elaborate, in order of highest to lowest potential for concern:
  *
- * <p>1. The {@link BuildConfigurationValue.Key} must be post-transition and thus ready for
- * immediate use in dependency resolution and analysis. In practice, this means that if the rule has
- * an incoming-edge transition (cfg in {@link RuleClass}) or there are global trimming transitions,
+ * <p>1. The {@link BuildConfigurationKey} must be post-transition and thus ready for immediate use
+ * in dependency resolution and analysis. In practice, this means that if the rule has an
+ * incoming-edge transition (cfg in {@link RuleClass}) or there are global trimming transitions,
  * THOSE TRANSITIONS MUST ALREADY BE DONE before creating the key. Failure to do so will lead to
- * build graphs with ConfiguredTarget that have seemingly impossible {@link BuildConfiguration} (due
- * to the skipped transitions).
+ * build graphs with ConfiguredTarget that have seemingly impossible {@link BuildConfigurationValue}
+ * (due to the skipped transitions).
  *
- * <p>2. The {@link BuildConfigurationValue.Key} must be canonical. Multiple keys can correspond to
- * the same {@link BuildConfiguration}. The canonical key is the one returned by {@link
- * BuildConfigurationValue.key}. Failure to use a canonical key can result in build graphs with
+ * <p>2. The {@link BuildConfigurationKey} must be canonical. Multiple keys can correspond to the
+ * same {@link BuildConfigurationValue}. The canonical key is the one returned by {@link
+ * BuildConfigurationValue#getKey}. Failure to use a canonical key can result in build graphs with
  * multiple seemingly-identical ConfiguredTarget that have the same ({@link Label}, {@link
- * BuildConfiguration}) pair. This is non-performant in all cases and incorrect if those
+ * BuildConfigurationValue}) pair. This is non-performant in all cases and incorrect if those
  * duplications lead to action conflicts due to unsharable actions.
  *
- * <p>3. A build should not request keys with equal ({@link Label}, {@link BuildConfiguration})
+ * <p>3. A build should not request keys with equal ({@link Label}, {@link BuildConfigurationValue})
  * pairs but different execution platform override {@link Label} if the invoked rule will register
  * actions. (This is potentially OK if all outputs of all registered actions incorporate the
  * execution platform in their name unless the build also requests keys without an override that
  * happen to resolve to the same execution platform.) In practice, this issue has not been seen in
  * any 'real' builds; however, pathologically failure could lead to multiple (potentially different)
- * ConfiguredTarget that have the same ({@link Label}, {@link BuildConfiguration}) pair.
+ * ConfiguredTarget that have the same ({@link Label}, {@link BuildConfigurationValue}) pair.
  *
  * <p>Note that this key may be used to look up the generating action of an artifact.
  */
@@ -69,12 +69,11 @@
   private static final Interner<ConfiguredTargetKey> interner = BlazeInterners.newWeakInterner();
 
   private final Label label;
-  @Nullable private final BuildConfigurationValue.Key configurationKey;
+  @Nullable private final BuildConfigurationKey configurationKey;
 
   private final transient int hashCode;
 
-  ConfiguredTargetKey(
-      Label label, @Nullable BuildConfigurationValue.Key configurationKey, int hashCode) {
+  ConfiguredTargetKey(Label label, @Nullable BuildConfigurationKey configurationKey, int hashCode) {
     this.label = checkNotNull(label);
     this.configurationKey = configurationKey;
     this.hashCode = hashCode;
@@ -82,8 +81,7 @@
 
   @AutoCodec.VisibleForSerialization
   @AutoCodec.Instantiator
-  static ConfiguredTargetKey create(
-      Label label, @Nullable BuildConfigurationValue.Key configurationKey) {
+  static ConfiguredTargetKey create(Label label, @Nullable BuildConfigurationKey configurationKey) {
     int hashCode = computeHashCode(label, configurationKey, /*executionPlatformLabel=*/ null);
     return interner.intern(new ConfiguredTargetKey(label, configurationKey, hashCode));
   }
@@ -106,7 +104,7 @@
   }
 
   @Nullable
-  public final BuildConfigurationValue.Key getConfigurationKey() {
+  public final BuildConfigurationKey getConfigurationKey() {
     return configurationKey;
   }
 
@@ -122,7 +120,7 @@
 
   private static int computeHashCode(
       Label label,
-      @Nullable BuildConfigurationValue.Key configurationKey,
+      @Nullable BuildConfigurationKey configurationKey,
       @Nullable Label executionPlatformLabel) {
     int configVal = configurationKey == null ? 79 : configurationKey.hashCode();
     int executionPlatformLabelVal =
@@ -175,7 +173,7 @@
 
     private ToolchainDependencyConfiguredTargetKey(
         Label label,
-        @Nullable BuildConfigurationValue.Key configurationKey,
+        @Nullable BuildConfigurationKey configurationKey,
         int hashCode,
         Label executionPlatformLabel) {
       super(label, configurationKey, hashCode);
@@ -186,7 +184,7 @@
     @AutoCodec.Instantiator
     static ToolchainDependencyConfiguredTargetKey create(
         Label label,
-        @Nullable BuildConfigurationValue.Key configurationKey,
+        @Nullable BuildConfigurationKey configurationKey,
         Label executionPlatformLabel) {
       int hashCode = computeHashCode(label, configurationKey, executionPlatformLabel);
       return toolchainDependencyConfiguredTargetKeyInterner.intern(
@@ -208,7 +206,7 @@
   /** A helper class to create instances of {@link ConfiguredTargetKey}. */
   public static final class Builder {
     private Label label = null;
-    private BuildConfigurationValue.Key configurationKey = null;
+    private BuildConfigurationKey configurationKey = null;
     private Label executionPlatformLabel = null;
 
     private Builder() {}
@@ -232,17 +230,13 @@
       return this;
     }
 
-    /** Sets the {@link BuildConfiguration} for the configured target. */
-    public Builder setConfiguration(@Nullable BuildConfiguration buildConfiguration) {
-      if (buildConfiguration == null) {
-        return setConfigurationKey(null);
-      } else {
-        return setConfigurationKey(BuildConfigurationValue.key(buildConfiguration));
-      }
+    /** Sets the {@link BuildConfigurationValue} for the configured target. */
+    public Builder setConfiguration(@Nullable BuildConfigurationValue buildConfiguration) {
+      return setConfigurationKey(buildConfiguration == null ? null : buildConfiguration.getKey());
     }
 
     /** Sets the configuration key for the configured target. */
-    public Builder setConfigurationKey(@Nullable BuildConfigurationValue.Key configurationKey) {
+    public Builder setConfigurationKey(@Nullable BuildConfigurationKey configurationKey) {
       this.configurationKey = configurationKey;
       return this;
     }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PlatformMappingValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/PlatformMappingValue.java
index d2d5687..2f614ae 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PlatformMappingValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PlatformMappingValue.java
@@ -48,7 +48,7 @@
 
 /**
  * Stores contents of a platforms/flags mapping file for transforming one {@link
- * BuildConfigurationValue.Key} into another.
+ * BuildConfigurationKey} into another.
  *
  * <p>See <a href=https://docs.google.com/document/d/1Vg_tPgiZbSrvXcJ403vZVAGlsWhH9BUDrAxMOYnO0Ls>
  * the design</a> for more details on how the mapping can be defined and the desired logic on how it
@@ -140,7 +140,7 @@
   private final ImmutableMap<ImmutableSet<String>, Label> flagsToPlatforms;
   private final ImmutableSet<Class<? extends FragmentOptions>> optionsClasses;
   private final LoadingCache<ImmutableSet<String>, OptionsParsingResult> parserCache;
-  private final LoadingCache<BuildConfigurationValue.Key, BuildConfigurationValue.Key> mappingCache;
+  private final LoadingCache<BuildConfigurationKey, BuildConfigurationKey> mappingCache;
 
   /**
    * Creates a new mapping value which will match on the given platforms (if a target platform is
@@ -167,7 +167,7 @@
   }
 
   /**
-   * Maps one {@link BuildConfigurationValue.Key} to another by way of mappings provided in a file.
+   * Maps one {@link BuildConfigurationKey} to another by way of mappings provided in a file.
    *
    * <p>The <a href=https://docs.google.com/document/d/1Vg_tPgiZbSrvXcJ403vZVAGlsWhH9BUDrAxMOYnO0Ls>
    * full design</a> contains the details for the mapping logic but in short:
@@ -186,8 +186,7 @@
    * @throws IllegalArgumentException if the original does not contain a {@link PlatformOptions}
    *     fragment
    */
-  public BuildConfigurationValue.Key map(BuildConfigurationValue.Key original)
-      throws OptionsParsingException {
+  public BuildConfigurationKey map(BuildConfigurationKey original) throws OptionsParsingException {
     try {
       return mappingCache.get(original);
     } catch (CompletionException e) {
@@ -196,7 +195,7 @@
     }
   }
 
-  private BuildConfigurationValue.Key computeMapping(BuildConfigurationValue.Key original)
+  private BuildConfigurationKey computeMapping(BuildConfigurationKey original)
       throws OptionsParsingException {
     BuildOptions originalOptions = original.getOptions();
 
@@ -238,8 +237,7 @@
       }
     }
 
-    return BuildConfigurationValue.keyWithoutPlatformMapping(
-        original.getFragments(), modifiedOptions);
+    return BuildConfigurationKey.withoutPlatformMapping(original.getFragments(), modifiedOptions);
   }
 
   private OptionsParsingResult parseWithCache(ImmutableSet<String> args)
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java
index 1a92d5e..45a4629 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java
@@ -22,7 +22,7 @@
 import com.google.devtools.build.lib.analysis.DependencyKey;
 import com.google.devtools.build.lib.analysis.PlatformOptions;
 import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
 import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
 import com.google.devtools.build.lib.analysis.config.ConfigurationResolver;
@@ -93,17 +93,17 @@
     List<BuildOptions> topLevelBuildOptions =
         getTopLevelBuildOptions(targetOptions, options.getMultiCpu());
 
-    ImmutableList.Builder<BuildConfigurationValue.Key> targetConfigurationKeysBuilder =
+    ImmutableList.Builder<BuildConfigurationKey> targetConfigurationKeysBuilder =
         ImmutableList.builderWithExpectedSize(topLevelBuildOptions.size());
-    BuildConfigurationValue.Key hostConfigurationKey;
+    BuildConfigurationKey hostConfigurationKey;
     try {
       hostConfigurationKey =
-          BuildConfigurationValue.keyWithPlatformMapping(
+          BuildConfigurationKey.withPlatformMapping(
               platformMappingValue, allFragments, hostOptions);
       for (BuildOptions buildOptions :
           getTopLevelBuildOptions(targetOptions, options.getMultiCpu())) {
         targetConfigurationKeysBuilder.add(
-            BuildConfigurationValue.keyWithPlatformMapping(
+            BuildConfigurationKey.withPlatformMapping(
                 platformMappingValue, allFragments, buildOptions));
       }
     } catch (OptionsParsingException e) {
@@ -117,7 +117,7 @@
       throw new PrepareAnalysisPhaseFunctionException(e);
     }
 
-    ImmutableList<BuildConfigurationValue.Key> targetConfigurationKeys =
+    ImmutableList<BuildConfigurationKey> targetConfigurationKeys =
         targetConfigurationKeysBuilder.build();
     Map<SkyKey, SkyValue> configs = env.getValues(targetConfigurationKeys);
 
@@ -127,7 +127,7 @@
     targetConfigurationKeys.stream()
         .map(configs::get)
         .filter(Objects::nonNull)
-        .map(v -> ((BuildConfigurationValue) v).getConfiguration())
+        .map(BuildConfigurationValue.class::cast)
         .forEach(config -> config.reportInvalidOptions(nosyEventHandler));
     if (nosyEventHandler.hasErrors()) {
       throw new PrepareAnalysisPhaseFunctionException(
@@ -148,9 +148,8 @@
     // groups.
     LinkedHashSet<TargetAndConfiguration> nodes = new LinkedHashSet<>(targets.size());
     for (Target target : targets) {
-      for (BuildConfigurationValue.Key configKey : targetConfigurationKeys) {
-        BuildConfiguration config =
-            ((BuildConfigurationValue) configs.get(configKey)).getConfiguration();
+      for (BuildConfigurationKey configKey : targetConfigurationKeys) {
+        BuildConfigurationValue config = (BuildConfigurationValue) configs.get(configKey);
         nodes.add(new TargetAndConfiguration(target, config));
       }
     }
@@ -160,7 +159,7 @@
     // for now, to satisfy its API we resolve transitions and repackage each target as a Dependency
     // (with a NONE transition if necessary).
     // Keep this in sync with AnalysisUtils#getTargetsWithConfigs.
-    Multimap<BuildConfiguration, DependencyKey> asDeps =
+    Multimap<BuildConfigurationValue, DependencyKey> asDeps =
         AnalysisUtils.targetsToDeps(nodes, ruleClassProvider);
     LinkedHashSet<TargetAndConfiguration> topLevelTargetsWithConfigs;
     try {
@@ -212,7 +211,7 @@
   private LinkedHashSet<TargetAndConfiguration> resolveConfigurations(
       SkyFunction.Environment env,
       Iterable<TargetAndConfiguration> nodes,
-      Multimap<BuildConfiguration, DependencyKey> asDeps)
+      Multimap<BuildConfigurationValue, DependencyKey> asDeps)
       throws InterruptedException, TransitionException, OptionsParsingException {
     Map<Label, Target> labelsToTargets = new LinkedHashMap<>();
     for (TargetAndConfiguration node : nodes) {
@@ -223,13 +222,14 @@
     // could be successfully Skyframe-evaluated.
     Map<TargetAndConfiguration, TargetAndConfiguration> successfullyEvaluatedTargets =
         new LinkedHashMap<>();
-    for (BuildConfiguration fromConfig : asDeps.keySet()) {
-      Multimap<DependencyKey, BuildConfiguration> trimmedTargets =
+    for (BuildConfigurationValue fromConfig : asDeps.keySet()) {
+      Multimap<DependencyKey, BuildConfigurationValue> trimmedTargets =
           getConfigurations(env, fromConfig.getOptions(), asDeps.get(fromConfig));
       if (trimmedTargets == null) {
         continue;
       }
-      for (Map.Entry<DependencyKey, BuildConfiguration> trimmedTarget : trimmedTargets.entries()) {
+      for (Map.Entry<DependencyKey, BuildConfigurationValue> trimmedTarget :
+          trimmedTargets.entries()) {
         Target target = labelsToTargets.get(trimmedTarget.getKey().getLabel());
         successfullyEvaluatedTargets.put(
             new TargetAndConfiguration(target, fromConfig),
@@ -251,10 +251,10 @@
 
   // Keep in sync with {@link SkyframeExecutor#getConfigurations}.
   // Note: this implementation runs inside Skyframe, so it has access to SkyFunction.Environment.
-  private Multimap<DependencyKey, BuildConfiguration> getConfigurations(
+  private Multimap<DependencyKey, BuildConfigurationValue> getConfigurations(
       SkyFunction.Environment env, BuildOptions fromOptions, Iterable<DependencyKey> keys)
       throws InterruptedException, TransitionException, OptionsParsingException {
-    Multimap<DependencyKey, BuildConfiguration> builder = ArrayListMultimap.create();
+    Multimap<DependencyKey, BuildConfigurationValue> builder = ArrayListMultimap.create();
 
     FragmentClassSet allFragments = ruleClassProvider.getFragmentRegistry().getAllFragments();
 
@@ -284,7 +284,7 @@
               .values();
       for (BuildOptions toOption : toOptions) {
         configSkyKeys.add(
-            BuildConfigurationValue.keyWithPlatformMapping(
+            BuildConfigurationKey.withPlatformMapping(
                 platformMappingValue, allFragments, toOption));
       }
     }
@@ -310,14 +310,13 @@
               .values();
       for (BuildOptions toOption : toOptions) {
         SkyKey configKey =
-            BuildConfigurationValue.keyWithPlatformMapping(
-                platformMappingValue, allFragments, toOption);
+            BuildConfigurationKey.withPlatformMapping(platformMappingValue, allFragments, toOption);
         BuildConfigurationValue configValue =
-            ((BuildConfigurationValue) configsResult.get(configKey));
+            (BuildConfigurationValue) configsResult.get(configKey);
         // configValue will be null here if there was an exception thrown during configuration
         // creation. This will be reported elsewhere.
         if (configValue != null) {
-          builder.put(key, configValue.getConfiguration());
+          builder.put(key, configValue);
         }
       }
     }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseValue.java
index 2556a89..d722007 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseValue.java
@@ -20,8 +20,8 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedSet;
 import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
 import com.google.devtools.build.lib.analysis.config.ConfigurationResolver.TopLevelTargetsAndConfigsResult;
 import com.google.devtools.build.lib.analysis.config.FragmentClassSet;
@@ -63,13 +63,13 @@
 @ThreadSafe
 @AutoCodec
 public final class PrepareAnalysisPhaseValue implements SkyValue {
-  private final BuildConfigurationValue.Key hostConfigurationKey;
-  private final ImmutableList<BuildConfigurationValue.Key> targetConfigurationKeys;
+  private final BuildConfigurationKey hostConfigurationKey;
+  private final ImmutableList<BuildConfigurationKey> targetConfigurationKeys;
   private final ImmutableList<ConfiguredTargetKey> topLevelCtKeys;
 
   PrepareAnalysisPhaseValue(
-      BuildConfigurationValue.Key hostConfigurationKey,
-      ImmutableList<BuildConfigurationValue.Key> targetConfigurationKeys,
+      BuildConfigurationKey hostConfigurationKey,
+      ImmutableList<BuildConfigurationKey> targetConfigurationKeys,
       ImmutableList<ConfiguredTargetKey> topLevelCtKeys) {
     this.hostConfigurationKey = Preconditions.checkNotNull(hostConfigurationKey);
     this.targetConfigurationKeys = Preconditions.checkNotNull(targetConfigurationKeys);
@@ -83,9 +83,9 @@
   public BuildConfigurationCollection getConfigurations(
       ExtendedEventHandler eventHandler, SkyframeExecutor skyframeExecutor)
           throws InvalidConfigurationException {
-    BuildConfiguration hostConfiguration =
+    BuildConfigurationValue hostConfiguration =
         skyframeExecutor.getConfiguration(eventHandler, hostConfigurationKey);
-    ImmutableList<BuildConfiguration> targetConfigurations =
+    ImmutableList<BuildConfigurationValue> targetConfigurations =
         ImmutableList.copyOf(
             skyframeExecutor.getConfigurations(eventHandler, targetConfigurationKeys).values());
     return new BuildConfigurationCollection(targetConfigurations, hostConfiguration);
@@ -102,7 +102,7 @@
   public TopLevelTargetsAndConfigsResult getTopLevelCts(
       ExtendedEventHandler eventHandler, SkyframeExecutor skyframeExecutor) {
     List<TargetAndConfiguration> result = new ArrayList<>();
-    Map<BuildConfigurationValue.Key, BuildConfiguration> configs =
+    Map<BuildConfigurationKey, BuildConfigurationValue> configs =
         skyframeExecutor.getConfigurations(
             eventHandler,
             topLevelCtKeys.stream()
@@ -124,7 +124,7 @@
         hasError = true;
         continue;
       }
-      BuildConfiguration config =
+      BuildConfigurationValue config =
           key.getConfigurationKey() == null ? null : configs.get(key.getConfigurationKey());
       result.add(new TargetAndConfiguration(target, config));
     }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunction.java
index 60d6ca2..cc47b00 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunction.java
@@ -21,7 +21,7 @@
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.ConfiguredTargetValue;
 import com.google.devtools.build.lib.analysis.PlatformConfiguration;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
 import com.google.devtools.build.lib.analysis.platform.PlatformProviderUtils;
 import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionValue;
@@ -67,7 +67,7 @@
   public SkyValue compute(SkyKey skyKey, Environment env)
       throws RegisteredExecutionPlatformsFunctionException, InterruptedException {
 
-    BuildConfigurationValue buildConfigurationValue =
+    BuildConfigurationValue configuration =
         (BuildConfigurationValue)
             env.getValue(((RegisteredExecutionPlatformsValue.Key) skyKey).getConfigurationKey());
     RepositoryMappingValue mainRepoMapping =
@@ -75,7 +75,6 @@
     if (env.valuesMissing()) {
       return null;
     }
-    BuildConfiguration configuration = buildConfigurationValue.getConfiguration();
 
     TargetPattern.Parser mainRepoParser =
         new TargetPattern.Parser(
@@ -186,7 +185,7 @@
   }
 
   private static ImmutableList<ConfiguredTargetKey> configureRegisteredExecutionPlatforms(
-      Environment env, BuildConfiguration configuration, List<Label> labels)
+      Environment env, BuildConfigurationValue configuration, List<Label> labels)
       throws InterruptedException, RegisteredExecutionPlatformsFunctionException {
     ImmutableList<ConfiguredTargetKey> keys =
         labels.stream()
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsValue.java
index b552777..df534c0 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsValue.java
@@ -31,7 +31,7 @@
 public abstract class RegisteredExecutionPlatformsValue implements SkyValue {
 
   /** Returns the {@link SkyKey} for {@link RegisteredExecutionPlatformsValue}s. */
-  public static SkyKey key(BuildConfigurationValue.Key configurationKey) {
+  public static SkyKey key(BuildConfigurationKey configurationKey) {
     return Key.of(configurationKey);
   }
 
@@ -41,15 +41,15 @@
   static class Key implements SkyKey {
     private static final Interner<Key> interners = BlazeInterners.newWeakInterner();
 
-    private final BuildConfigurationValue.Key configurationKey;
+    private final BuildConfigurationKey configurationKey;
 
-    private Key(BuildConfigurationValue.Key configurationKey) {
+    private Key(BuildConfigurationKey configurationKey) {
       this.configurationKey = configurationKey;
     }
 
     @AutoCodec.Instantiator
     @AutoCodec.VisibleForSerialization
-    static Key of(BuildConfigurationValue.Key configurationKey) {
+    static Key of(BuildConfigurationKey configurationKey) {
       return interners.intern(new Key(configurationKey));
     }
 
@@ -58,7 +58,7 @@
       return SkyFunctions.REGISTERED_EXECUTION_PLATFORMS;
     }
 
-    BuildConfigurationValue.Key getConfigurationKey() {
+    BuildConfigurationKey getConfigurationKey() {
       return configurationKey;
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunction.java
index d22fe77..1e0e17b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunction.java
@@ -21,7 +21,7 @@
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.ConfiguredTargetValue;
 import com.google.devtools.build.lib.analysis.PlatformConfiguration;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.analysis.platform.DeclaredToolchainInfo;
 import com.google.devtools.build.lib.analysis.platform.PlatformProviderUtils;
 import com.google.devtools.build.lib.bazel.bzlmod.BazelModuleResolutionValue;
@@ -59,7 +59,7 @@
   public SkyValue compute(SkyKey skyKey, Environment env)
       throws SkyFunctionException, InterruptedException {
 
-    BuildConfigurationValue buildConfigurationValue =
+    BuildConfigurationValue configuration =
         (BuildConfigurationValue)
             env.getValue(((RegisteredToolchainsValue.Key) skyKey).getConfigurationKey());
     RepositoryMappingValue mainRepoMapping =
@@ -67,7 +67,6 @@
     if (env.valuesMissing()) {
       return null;
     }
-    BuildConfiguration configuration = buildConfigurationValue.getConfiguration();
 
     TargetPattern.Parser mainRepoParser =
         new TargetPattern.Parser(
@@ -176,7 +175,7 @@
   }
 
   private static ImmutableList<DeclaredToolchainInfo> configureRegisteredToolchains(
-      Environment env, BuildConfiguration configuration, List<Label> labels)
+      Environment env, BuildConfigurationValue configuration, List<Label> labels)
       throws InterruptedException, RegisteredToolchainsFunctionException {
     ImmutableList<SkyKey> keys =
         labels.stream()
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsValue.java
index 17c7fca..49e8042 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsValue.java
@@ -33,7 +33,7 @@
 public abstract class RegisteredToolchainsValue implements SkyValue {
 
   /** Returns the {@link SkyKey} for {@link RegisteredToolchainsValue}s. */
-  public static Key key(BuildConfigurationValue.Key configurationKey) {
+  public static Key key(BuildConfigurationKey configurationKey) {
     return Key.of(configurationKey);
   }
 
@@ -42,15 +42,15 @@
   static class Key implements SkyKey {
     private static final Interner<Key> interners = BlazeInterners.newWeakInterner();
 
-    private final BuildConfigurationValue.Key configurationKey;
+    private final BuildConfigurationKey configurationKey;
 
-    private Key(BuildConfigurationValue.Key configurationKey) {
+    private Key(BuildConfigurationKey configurationKey) {
       this.configurationKey = configurationKey;
     }
 
     @AutoCodec.Instantiator
     @AutoCodec.VisibleForSerialization
-    static Key of(BuildConfigurationValue.Key configurationKey) {
+    static Key of(BuildConfigurationKey configurationKey) {
       return interners.intern(new Key(configurationKey));
     }
 
@@ -59,7 +59,7 @@
       return SkyFunctions.REGISTERED_TOOLCHAINS;
     }
 
-    BuildConfigurationValue.Key getConfigurationKey() {
+    BuildConfigurationKey getConfigurationKey() {
       return configurationKey;
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SingleToolchainResolutionFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/SingleToolchainResolutionFunction.java
index f8eef44..bbdbf6a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SingleToolchainResolutionFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SingleToolchainResolutionFunction.java
@@ -21,7 +21,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.analysis.PlatformConfiguration;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
 import com.google.devtools.build.lib.analysis.platform.ConstraintCollection;
 import com.google.devtools.build.lib.analysis.platform.ConstraintSettingInfo;
@@ -58,11 +58,11 @@
 
     // This call could be combined with the call below, but this SkyFunction is evaluated so rarely
     // it's not worth optimizing.
-    BuildConfigurationValue value = (BuildConfigurationValue) env.getValue(key.configurationKey());
+    BuildConfigurationValue configuration =
+        (BuildConfigurationValue) env.getValue(key.configurationKey());
     if (env.valuesMissing()) {
       return null;
     }
-    BuildConfiguration configuration = value.getConfiguration();
 
     // Get all toolchains.
     RegisteredToolchainsValue toolchains;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SingleToolchainResolutionValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/SingleToolchainResolutionValue.java
index a503798..e021b47 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SingleToolchainResolutionValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SingleToolchainResolutionValue.java
@@ -35,7 +35,7 @@
 
   // A key representing the input data.
   public static SingleToolchainResolutionKey key(
-      BuildConfigurationValue.Key configurationKey,
+      BuildConfigurationKey configurationKey,
       Label toolchainTypeLabel,
       ConfiguredTargetKey targetPlatformKey,
       List<ConfiguredTargetKey> availableExecutionPlatformKeys) {
@@ -48,7 +48,7 @@
   }
 
   public static SingleToolchainResolutionKey key(
-      BuildConfigurationValue.Key configurationKey,
+      BuildConfigurationKey configurationKey,
       Label toolchainTypeLabel,
       ConfiguredTargetKey targetPlatformKey,
       List<ConfiguredTargetKey> availableExecutionPlatformKeys,
@@ -72,7 +72,7 @@
       return SkyFunctions.SINGLE_TOOLCHAIN_RESOLUTION;
     }
 
-    abstract BuildConfigurationValue.Key configurationKey();
+    abstract BuildConfigurationKey configurationKey();
 
     public abstract Label toolchainTypeLabel();
 
@@ -84,7 +84,7 @@
 
     @AutoCodec.Instantiator
     static SingleToolchainResolutionKey create(
-        BuildConfigurationValue.Key configurationKey,
+        BuildConfigurationKey configurationKey,
         Label toolchainTypeLabel,
         ConfiguredTargetKey targetPlatformKey,
         List<ConfiguredTargetKey> availableExecutionPlatformKeys,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
index a7eb585..6c5f9fe 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
@@ -53,8 +53,8 @@
 import com.google.devtools.build.lib.analysis.ToolchainCollection;
 import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
 import com.google.devtools.build.lib.analysis.ViewCreationFailedException;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
 import com.google.devtools.build.lib.analysis.config.BuildOptions.OptionsDiff;
 import com.google.devtools.build.lib.analysis.config.ConfigConditions;
@@ -144,7 +144,7 @@
   private final ConfiguredRuleClassProvider ruleClassProvider;
 
   // The host configuration containing all fragments used by this build's transitive closure.
-  private BuildConfiguration topLevelHostConfiguration;
+  private BuildConfigurationValue topLevelHostConfiguration;
 
   private BuildConfigurationCollection configurations;
 
@@ -206,15 +206,16 @@
       return null;
     }
 
-    ImmutableList<BuildConfiguration> oldTargetConfigs =
+    ImmutableList<BuildConfigurationValue> oldTargetConfigs =
         this.configurations.getTargetConfigurations();
-    ImmutableList<BuildConfiguration> newTargetConfigs = configurations.getTargetConfigurations();
+    ImmutableList<BuildConfigurationValue> newTargetConfigs =
+        configurations.getTargetConfigurations();
 
     // TODO(schmitt): We are only checking the first of the new configurations, even though (through
     //  split transitions) we could have more than one. There is some special handling for
     //  --cpu changing below but other options may also be changed and should be covered.
-    BuildConfiguration oldConfig = oldTargetConfigs.get(0);
-    BuildConfiguration newConfig = newTargetConfigs.get(0);
+    BuildConfigurationValue oldConfig = oldTargetConfigs.get(0);
+    BuildConfigurationValue newConfig = newTargetConfigs.get(0);
     OptionsDiff diff = BuildOptions.diff(oldConfig.getOptions(), newConfig.getOptions());
 
     ImmutableSet<OptionDefinition> nativeCacheInvalidatingDifferences =
@@ -264,9 +265,9 @@
   // TODO(schmitt): This method assumes that the only option that can cause multiple target
   //  configurations is --cpu which (with the presence of split transitions) is no longer true.
   private ImmutableSet<OptionDefinition> getNativeCacheInvalidatingDifferences(
-      ImmutableList<BuildConfiguration> oldTargetConfigs,
-      ImmutableList<BuildConfiguration> newTargetConfigs,
-      BuildConfiguration newConfig,
+      ImmutableList<BuildConfigurationValue> oldTargetConfigs,
+      ImmutableList<BuildConfigurationValue> newTargetConfigs,
+      BuildConfigurationValue newConfig,
       OptionsDiff diff) {
     Stream<OptionDefinition> nativeCacheInvalidatingDifferences =
         diff.getFirst().keySet().stream()
@@ -292,9 +293,9 @@
           nativeCacheInvalidatingDifferences.filter(
               (definition) -> !CoreOptions.CPU.equals(definition));
       ImmutableSet<String> oldCpus =
-          oldTargetConfigs.stream().map(BuildConfiguration::getCpu).collect(toImmutableSet());
+          oldTargetConfigs.stream().map(BuildConfigurationValue::getCpu).collect(toImmutableSet());
       ImmutableSet<String> newCpus =
-          newTargetConfigs.stream().map(BuildConfiguration::getCpu).collect(toImmutableSet());
+          newTargetConfigs.stream().map(BuildConfigurationValue::getCpu).collect(toImmutableSet());
       if (!Objects.equals(oldCpus, newCpus)) {
         // --experimental_multi_cpu has changed, so inject that in the diff stream.
         nativeCacheInvalidatingDifferences =
@@ -347,7 +348,7 @@
    * Sets the host configuration consisting of all fragments that will be used by the top level
    * targets' transitive closures.
    */
-  private void setTopLevelHostConfiguration(BuildConfiguration topLevelHostConfiguration) {
+  private void setTopLevelHostConfiguration(BuildConfigurationValue topLevelHostConfiguration) {
     if (!topLevelHostConfiguration.equals(this.topLevelHostConfiguration)) {
       this.topLevelHostConfiguration = topLevelHostConfiguration;
     }
@@ -375,7 +376,7 @@
       ExtendedEventHandler eventHandler,
       List<ConfiguredTargetKey> ctKeys,
       ImmutableList<TopLevelAspectsKey> topLevelAspectsKeys,
-      Supplier<Map<BuildConfigurationValue.Key, BuildConfiguration>> configurationLookupSupplier,
+      Supplier<Map<BuildConfigurationKey, BuildConfigurationValue>> configurationLookupSupplier,
       TopLevelArtifactContext topLevelArtifactContextForConflictPruning,
       EventBus eventBus,
       boolean keepGoing,
@@ -565,7 +566,7 @@
           }
           AnalysisFailedCause failedCause =
               makeArtifactConflictAnalysisFailedCause(configurationLookupSupplier, e.get());
-          BuildConfigurationValue.Key configKey =
+          BuildConfigurationKey configKey =
               ctKey instanceof ConfiguredTargetKey
                   ? ((ConfiguredTargetKey) ctKey).getConfigurationKey()
                   : ((AspectKey) ctKey).getAspectConfigurationKey();
@@ -695,7 +696,7 @@
   }
 
   private static AnalysisFailedCause makeArtifactConflictAnalysisFailedCause(
-      Supplier<Map<BuildConfigurationValue.Key, BuildConfiguration>> configurationLookupSupplier,
+      Supplier<Map<BuildConfigurationKey, BuildConfigurationValue>> configurationLookupSupplier,
       ConflictException e) {
     try {
       throw e.rethrowTyped();
@@ -707,16 +708,16 @@
   }
 
   private static AnalysisFailedCause makeArtifactConflictAnalysisFailedCause(
-      Supplier<Map<BuildConfigurationValue.Key, BuildConfiguration>> configurationLookupSupplier,
+      Supplier<Map<BuildConfigurationKey, BuildConfigurationValue>> configurationLookupSupplier,
       ActionConflictException ace) {
     DetailedExitCode detailedExitCode = ace.getDetailedExitCode();
     Label causeLabel = ace.getArtifact().getArtifactOwner().getLabel();
-    BuildConfigurationValue.Key causeConfigKey = null;
+    BuildConfigurationKey causeConfigKey = null;
     if (ace.getArtifact().getArtifactOwner() instanceof ConfiguredTargetKey) {
       causeConfigKey =
           ((ConfiguredTargetKey) ace.getArtifact().getArtifactOwner()).getConfigurationKey();
     }
-    BuildConfiguration causeConfig =
+    BuildConfigurationValue causeConfig =
         causeConfigKey == null ? null : configurationLookupSupplier.get().get(causeConfigKey);
     return new AnalysisFailedCause(
         causeLabel,
@@ -797,14 +798,15 @@
    * keepGoing} is false.
    *
    * <p>Visible only for use by tests via {@link
-   * SkyframeExecutor#getConfiguredTargetMapForTesting(ExtendedEventHandler, BuildConfiguration,
-   * Iterable)}. When called there, {@code eventBus} must be null to indicate that this is a test,
-   * and so there may be additional {@link SkyKey}s in the {@code result} that are not {@link
-   * AspectKeyCreator}s or {@link ConfiguredTargetKey}s. Those keys will be ignored.
+   * SkyframeExecutor#getConfiguredTargetMapForTesting(ExtendedEventHandler,
+   * BuildConfigurationValue, Iterable)}. When called there, {@code eventBus} must be null to
+   * indicate that this is a test, and so there may be additional {@link SkyKey}s in the {@code
+   * result} that are not {@link AspectKeyCreator}s or {@link ConfiguredTargetKey}s. Those keys will
+   * be ignored.
    */
   static Pair<Boolean, ViewCreationFailedException> processErrors(
       EvaluationResult<? extends SkyValue> result,
-      Supplier<Map<BuildConfigurationValue.Key, BuildConfiguration>> configurationLookupSupplier,
+      Supplier<Map<BuildConfigurationKey, BuildConfigurationValue>> configurationLookupSupplier,
       SkyframeExecutor skyframeExecutor,
       ExtendedEventHandler eventHandler,
       boolean keepGoing,
@@ -897,7 +899,7 @@
       } else if (cause instanceof NoSuchPackageException) {
         // This branch is only taken in --nokeep_going builds. In a --keep_going build, the
         // AnalysisFailedCause is properly reported through the ConfiguredValueCreationException.
-        BuildConfiguration configuration =
+        BuildConfigurationValue configuration =
             configurationLookupSupplier.get().get(label.getConfigurationKey());
         ConfigurationId configId = configuration.getEventId().getConfiguration();
         AnalysisFailedCause analysisFailedCause =
@@ -922,7 +924,7 @@
       }
 
       if (!inTest) {
-        BuildConfiguration configuration =
+        BuildConfigurationValue configuration =
             configurationLookupSupplier.get().get(label.getConfigurationKey());
         eventBus.post(
             new AnalysisFailureEvent(
@@ -1067,7 +1069,7 @@
       ActionLookupKey owner,
       ExtendedEventHandler eventHandler,
       Environment env,
-      BuildConfiguration config,
+      BuildConfigurationValue config,
       StarlarkBuiltinsValue starlarkBuiltinsValue) {
     boolean extendedSanityChecks = config != null && config.extendedSanityChecks();
     boolean allowAnalysisFailures = config != null && config.allowAnalysisFailures();
@@ -1092,7 +1094,7 @@
   @Nullable
   ConfiguredTarget createConfiguredTarget(
       Target target,
-      BuildConfiguration configuration,
+      BuildConfigurationValue configuration,
       CachingAnalysisEnvironment analysisEnvironment,
       ConfiguredTargetKey configuredTargetKey,
       OrderedSetMultimap<DependencyKind, ConfiguredTargetAndData> prerequisiteMap,
@@ -1124,7 +1126,7 @@
    * <p>This may only be called after {@link #setTopLevelHostConfiguration} has set the correct host
    * configuration at the top-level.
    */
-  public BuildConfiguration getHostConfiguration() {
+  public BuildConfigurationValue getHostConfiguration() {
     return topLevelHostConfiguration;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeDependencyResolver.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeDependencyResolver.java
index c176128..bc7cd48 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeDependencyResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeDependencyResolver.java
@@ -20,7 +20,7 @@
 import com.google.devtools.build.lib.analysis.DependencyKind;
 import com.google.devtools.build.lib.analysis.DependencyResolver;
 import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.ConfigurationId;
 import com.google.devtools.build.lib.causes.AnalysisFailedCause;
 import com.google.devtools.build.lib.causes.Cause;
@@ -145,7 +145,7 @@
                           fromTarget.getLabel(), label, label.getRepository(), e.getMessage())));
           continue;
         }
-        @Nullable BuildConfiguration configuration = fromNode.getConfiguration();
+        @Nullable BuildConfigurationValue configuration = fromNode.getConfiguration();
         @Nullable ConfigurationId configId = null;
         if (configuration != null) {
           configId =  configuration.getEventId().getConfiguration();
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index da36b1d..2bb0fd1 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -13,13 +13,16 @@
 // limitations under the License.
 package com.google.devtools.build.lib.skyframe;
 
+import static com.google.common.collect.ImmutableList.toImmutableList;
 import static com.google.devtools.build.lib.concurrent.Uninterruptibles.callUninterruptibly;
 import static com.google.devtools.build.lib.skyframe.ArtifactConflictFinder.ACTION_CONFLICTS;
 import static com.google.devtools.build.lib.skyframe.ArtifactConflictFinder.NUM_JOBS;
+import static java.util.stream.Collectors.toMap;
 
 import com.github.benmanes.caffeine.cache.Cache;
 import com.github.benmanes.caffeine.cache.Caffeine;
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Functions;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
@@ -85,8 +88,8 @@
 import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
 import com.google.devtools.build.lib.analysis.WorkspaceStatusAction;
 import com.google.devtools.build.lib.analysis.WorkspaceStatusAction.Factory;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
 import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
 import com.google.devtools.build.lib.analysis.config.ConfigurationResolver;
@@ -230,7 +233,6 @@
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
-import java.util.stream.Collectors;
 import javax.annotation.Nullable;
 import net.starlark.java.eval.StarlarkSemantics;
 
@@ -1141,14 +1143,14 @@
     return basicAnalysisInvalidatingPredicate(key) || key instanceof ActionLookupData;
   }
 
-  // We may also want to remove BuildConfigurationValue.Keys to fix a minor memory leak there.
+  // We may also want to remove BuildConfigurationKey to fix a minor memory leak there.
   private static boolean fullAnalysisInvalidatingPredicate(SkyKey key) {
-    return basicAnalysisInvalidatingPredicate(key) || key instanceof BuildConfigurationValue.Key;
+    return basicAnalysisInvalidatingPredicate(key) || key instanceof BuildConfigurationKey;
   }
 
   private static boolean fullAnalysisInvalidatingPredicateWithActions(SkyKey key) {
     return basicAnalysisInvalidatingPredicateWithActions(key)
-        || key instanceof BuildConfigurationValue.Key;
+        || key instanceof BuildConfigurationKey;
   }
 
   private WorkspaceStatusAction makeWorkspaceStatusAction(String workspaceName) {
@@ -1538,14 +1540,14 @@
       configuredTargetProgress.reset();
     }
 
-    ImmutableList<BuildConfiguration> topLevelTargetConfigs =
+    ImmutableList<BuildConfigurationValue> topLevelTargetConfigs =
         getConfigurations(
             eventHandler,
             PrepareAnalysisPhaseFunction.getTopLevelBuildOptions(buildOptions, multiCpu),
             buildOptions,
             keepGoing);
 
-    BuildConfiguration firstTargetConfig = topLevelTargetConfigs.get(0);
+    BuildConfigurationValue firstTargetConfig = topLevelTargetConfigs.get(0);
 
     BuildOptions targetOptions = firstTargetConfig.getOptions();
     BuildOptionsView hostTransitionOptionsView =
@@ -1555,7 +1557,7 @@
         targetOptions.get(CoreOptions.class).useDistinctHostConfiguration
             ? HostTransition.INSTANCE.patch(hostTransitionOptionsView, eventHandler)
             : targetOptions;
-    BuildConfiguration hostConfig = getConfiguration(eventHandler, hostOptions, keepGoing);
+    BuildConfigurationValue hostConfig = getConfiguration(eventHandler, hostOptions, keepGoing);
 
     // TODO(gregce): cache invalid option errors in BuildConfigurationFunction, then use a dedicated
     // accessor (i.e. not the event handler) to trigger the exception below.
@@ -1759,7 +1761,7 @@
   @ThreadSafety.ThreadSafe
   public ImmutableList<ConfiguredTargetAndData> getConfiguredTargetsForTesting(
       ExtendedEventHandler eventHandler,
-      BuildConfiguration originalConfig,
+      BuildConfigurationValue originalConfig,
       Iterable<DependencyKey> keys)
       throws TransitionException, InvalidConfigurationException, InterruptedException {
     return getConfiguredTargetMapForTesting(eventHandler, originalConfig, keys).values().asList();
@@ -1777,7 +1779,7 @@
   @ThreadSafety.ThreadSafe
   public ImmutableMultimap<DependencyKey, ConfiguredTargetAndData> getConfiguredTargetMapForTesting(
       ExtendedEventHandler eventHandler,
-      BuildConfigurationValue.Key originalConfig,
+      BuildConfigurationKey originalConfig,
       Iterable<DependencyKey> keys)
       throws InvalidConfigurationException, InterruptedException {
     return getConfiguredTargetMapForTesting(
@@ -1797,12 +1799,12 @@
   private ImmutableMultimap<DependencyKey, ConfiguredTargetAndData>
       getConfiguredTargetMapForTesting(
           ExtendedEventHandler eventHandler,
-          BuildConfiguration originalConfig,
+          BuildConfigurationValue originalConfig,
           Iterable<DependencyKey> keys)
           throws InvalidConfigurationException, InterruptedException {
     checkActive();
 
-    Multimap<DependencyKey, BuildConfiguration> configs;
+    Multimap<DependencyKey, BuildConfigurationValue> configs;
     if (originalConfig != null) {
       configs =
           getConfigurations(eventHandler, originalConfig.getOptions(), keys).getConfigurationMap();
@@ -1820,7 +1822,7 @@
         // it couldn't be loaded). Exclude it from the results.
         continue;
       }
-      for (BuildConfiguration depConfig : configs.get(key)) {
+      for (BuildConfigurationValue depConfig : configs.get(key)) {
         skyKeys.add(
             ConfiguredTargetKey.builder()
                 .setLabel(key.getLabel())
@@ -1853,7 +1855,7 @@
           // it couldn't be loaded). Exclude it from the results.
           continue;
         }
-        for (BuildConfiguration depConfig : configs.get(key)) {
+        for (BuildConfigurationValue depConfig : configs.get(key)) {
           SkyKey configuredTargetKey =
               ConfiguredTargetKey.builder()
                   .setLabel(key.getLabel())
@@ -1896,13 +1898,13 @@
           try {
             ConfiguredTarget mergedTarget =
                 MergedConfiguredTarget.of(configuredTarget, configuredAspects);
-            BuildConfigurationValue.Key configKey = mergedTarget.getConfigurationKey();
-            BuildConfiguration resolvedConfig = depConfig;
+            BuildConfigurationKey configKey = mergedTarget.getConfigurationKey();
+            BuildConfigurationValue resolvedConfig = depConfig;
             if (configKey == null) {
               // Unfortunately, it's possible to get a configured target with a null configuration
               // when depConfig is non-null, so we need to explicitly override it in that case.
               resolvedConfig = null;
-            } else if (!configKey.equals(BuildConfigurationValue.key(depConfig))) {
+            } else if (!configKey.equals(depConfig.getKey())) {
               resolvedConfig = getConfiguration(eventHandler, mergedTarget.getConfigurationKey());
             }
             cts.put(
@@ -1924,12 +1926,10 @@
       aliasPackageValues = evaluateSkyKeys(eventHandler, aliasPackagesToFetch);
       keysToProcess = aliasKeysToRedo;
     }
-    Supplier<Map<BuildConfigurationValue.Key, BuildConfiguration>> configurationLookupSupplier =
+    Supplier<Map<BuildConfigurationKey, BuildConfigurationValue>> configurationLookupSupplier =
         () ->
             configs.values().stream()
-                .collect(
-                    Collectors.toMap(
-                        BuildConfigurationValue::key, java.util.function.Function.identity()));
+                .collect(toMap(BuildConfigurationValue::getKey, Functions.identity()));
     // We ignore the return value here because tests effectively run with --keep_going, and the
     // loading-phase-error bit is only needed if we're constructing a SkyframeAnalysisResult.
     SkyframeBuildView.processErrors(
@@ -1949,31 +1949,29 @@
    * @throws InvalidConfigurationException if the build options produces an invalid configuration
    */
   @Deprecated
-  public BuildConfiguration getConfiguration(
+  public BuildConfigurationValue getConfiguration(
       ExtendedEventHandler eventHandler, BuildOptions options, boolean keepGoing)
       throws InvalidConfigurationException {
     return Iterables.getOnlyElement(
         getConfigurations(eventHandler, ImmutableList.of(options), options, keepGoing));
   }
 
-  public BuildConfiguration getConfiguration(
-      ExtendedEventHandler eventHandler, BuildConfigurationValue.Key configurationKey) {
+  public BuildConfigurationValue getConfiguration(
+      ExtendedEventHandler eventHandler, BuildConfigurationKey configurationKey) {
     if (configurationKey == null) {
       return null;
     }
-    return ((BuildConfigurationValue)
-            evaluateSkyKeys(eventHandler, ImmutableList.of(configurationKey)).get(configurationKey))
-        .getConfiguration();
+    return (BuildConfigurationValue)
+        evaluateSkyKeys(eventHandler, ImmutableList.of(configurationKey)).get(configurationKey);
   }
 
-  public Map<BuildConfigurationValue.Key, BuildConfiguration> getConfigurations(
-      ExtendedEventHandler eventHandler, Collection<BuildConfigurationValue.Key> keys) {
+  public Map<BuildConfigurationKey, BuildConfigurationValue> getConfigurations(
+      ExtendedEventHandler eventHandler, Collection<BuildConfigurationKey> keys) {
     EvaluationResult<SkyValue> evaluationResult = evaluateSkyKeys(eventHandler, keys);
     return keys.stream()
         .collect(
-            Collectors.toMap(
-                java.util.function.Function.identity(),
-                (key) -> ((BuildConfigurationValue) evaluationResult.get(key)).getConfiguration()));
+            toMap(
+                Functions.identity(), key -> (BuildConfigurationValue) evaluationResult.get(key)));
   }
   /**
    * Returns the configurations corresponding to the given sets of build options. Output order is
@@ -1982,7 +1980,7 @@
    * @throws InvalidConfigurationException if any build options produces an invalid configuration
    */
   // TODO(ulfjack): Remove this legacy method after switching to the Skyframe-based implementation.
-  private ImmutableList<BuildConfiguration> getConfigurations(
+  private ImmutableList<BuildConfigurationValue> getConfigurations(
       ExtendedEventHandler eventHandler,
       List<BuildOptions> optionsList,
       BuildOptions referenceBuildOptions,
@@ -2028,8 +2026,8 @@
 
     // Prepare and return the results.
     return configSkyKeys.stream()
-        .map(key -> ((BuildConfigurationValue) evalResult.get(key)).getConfiguration())
-        .collect(ImmutableList.toImmutableList());
+        .map(key -> (BuildConfigurationValue) evalResult.get(key))
+        .collect(toImmutableList());
   }
 
   /**
@@ -2096,12 +2094,12 @@
       }
 
       for (BuildOptions toOption : toOptions) {
-        BuildConfigurationValue.Key configKey =
+        BuildConfigurationKey configKey =
             toConfigurationKey(platformMappingValue, allFragments, toOption);
         BuildConfigurationValue configValue =
             (BuildConfigurationValue) configsResult.get(configKey);
         if (configValue != null) {
-          builder.put(key, configValue.getConfiguration());
+          builder.put(key, configValue);
         } else if (configsResult.errorMap().containsKey(configKey)) {
           ErrorInfo configError = configsResult.getError(configKey);
           if (configError.getException() instanceof InvalidConfigurationException) {
@@ -2117,11 +2115,11 @@
     return builder.build();
   }
 
-  /** Returns every {@link BuildConfigurationValue.Key} in the graph. */
+  /** Returns every {@link BuildConfigurationKey} in the graph. */
   public Collection<SkyKey> getTransitiveConfigurationKeys() {
     return memoizingEvaluator.getDoneValues().keySet().stream()
         .filter(key -> SkyFunctions.BUILD_CONFIGURATION.equals(key.functionName()))
-        .collect(ImmutableList.toImmutableList());
+        .collect(toImmutableList());
   }
 
   private PlatformMappingValue getPlatformMappingValue(
@@ -2141,13 +2139,13 @@
     return (PlatformMappingValue) evaluationResult.get(platformMappingKey);
   }
 
-  private static BuildConfigurationValue.Key toConfigurationKey(
+  private static BuildConfigurationKey toConfigurationKey(
       PlatformMappingValue platformMappingValue,
       FragmentClassSet depFragments,
       BuildOptions toOption)
       throws InvalidConfigurationException {
     try {
-      return BuildConfigurationValue.keyWithPlatformMapping(
+      return BuildConfigurationKey.withPlatformMapping(
           platformMappingValue, depFragments, toOption);
     } catch (OptionsParsingException e) {
       throw new InvalidConfigurationException(Code.INVALID_BUILD_OPTIONS, e);
@@ -2241,28 +2239,26 @@
    * options.
    */
   @VisibleForTesting
-  public BuildConfiguration getConfigurationForTesting(
+  public BuildConfigurationValue getConfigurationForTesting(
       ExtendedEventHandler eventHandler, FragmentClassSet fragments, BuildOptions options)
       throws InterruptedException, OptionsParsingException, InvalidConfigurationException {
     SkyKey key =
-        BuildConfigurationValue.keyWithPlatformMapping(
+        BuildConfigurationKey.withPlatformMapping(
             getPlatformMappingValue(eventHandler, options), fragments, options);
-    BuildConfigurationValue result =
-        (BuildConfigurationValue)
-            evaluate(
-                    ImmutableList.of(key),
-                    /*keepGoing=*/ false,
-                    /*numThreads=*/ DEFAULT_THREAD_COUNT,
-                    eventHandler)
-                .get(key);
-    return result.getConfiguration();
+    return (BuildConfigurationValue)
+        evaluate(
+                ImmutableList.of(key),
+                /*keepGoing=*/ false,
+                /*numThreads=*/ DEFAULT_THREAD_COUNT,
+                eventHandler)
+            .get(key);
   }
 
   /** Returns a particular configured target. */
   @VisibleForTesting
   @Nullable
   public ConfiguredTarget getConfiguredTargetForTesting(
-      ExtendedEventHandler eventHandler, Label label, BuildConfiguration configuration)
+      ExtendedEventHandler eventHandler, Label label, BuildConfigurationValue configuration)
       throws TransitionException, InvalidConfigurationException, InterruptedException {
     return getConfiguredTargetForTesting(eventHandler, label, configuration, NoTransition.INSTANCE);
   }
@@ -2273,7 +2269,7 @@
   public ConfiguredTarget getConfiguredTargetForTesting(
       ExtendedEventHandler eventHandler,
       Label label,
-      BuildConfiguration configuration,
+      BuildConfigurationValue configuration,
       ConfigurationTransition transition)
       throws TransitionException, InvalidConfigurationException, InterruptedException {
     ConfiguredTargetAndData configuredTargetAndData =
@@ -2286,7 +2282,7 @@
   public ConfiguredTargetAndData getConfiguredTargetAndDataForTesting(
       ExtendedEventHandler eventHandler,
       Label label,
-      BuildConfiguration configuration,
+      BuildConfigurationValue configuration,
       ConfigurationTransition transition)
       throws TransitionException, InvalidConfigurationException, InterruptedException {
 
@@ -2303,7 +2299,7 @@
   @VisibleForTesting
   @Nullable
   public ConfiguredTargetAndData getConfiguredTargetAndDataForTesting(
-      ExtendedEventHandler eventHandler, Label label, BuildConfiguration configuration)
+      ExtendedEventHandler eventHandler, Label label, BuildConfigurationValue configuration)
       throws TransitionException, InvalidConfigurationException, InterruptedException {
     return getConfiguredTargetAndDataForTesting(
         eventHandler, label, configuration, NoTransition.INSTANCE);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainContextKey.java b/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainContextKey.java
index 3033a02..786b3bd 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainContextKey.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainContextKey.java
@@ -42,7 +42,7 @@
     return SkyFunctions.TOOLCHAIN_RESOLUTION;
   }
 
-  abstract BuildConfigurationValue.Key configurationKey();
+  abstract BuildConfigurationKey configurationKey();
 
   abstract ImmutableSet<Label> requiredToolchainTypeLabels();
 
@@ -55,7 +55,7 @@
   /** Builder for {@link ToolchainContextKey}. */
   @AutoValue.Builder
   public interface Builder {
-    Builder configurationKey(BuildConfigurationValue.Key key);
+    Builder configurationKey(BuildConfigurationKey key);
 
     Builder requiredToolchainTypeLabels(ImmutableSet<Label> requiredToolchainTypeLabels);
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainResolutionFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainResolutionFunction.java
index f579293..a8390ec 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainResolutionFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ToolchainResolutionFunction.java
@@ -27,7 +27,7 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Table;
 import com.google.devtools.build.lib.analysis.PlatformConfiguration;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.analysis.platform.ConstraintValueInfo;
 import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
 import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo;
@@ -70,12 +70,11 @@
           UnloadedToolchainContextImpl.builder().setKey(key);
 
       // Determine the configuration being used.
-      BuildConfigurationValue value =
+      BuildConfigurationValue configuration =
           (BuildConfigurationValue) env.getValue(key.configurationKey());
-      if (value == null) {
+      if (configuration == null) {
         throw new ValueMissingException();
       }
-      BuildConfiguration configuration = value.getConfiguration();
       PlatformConfiguration platformConfiguration =
           Preconditions.checkNotNull(configuration.getFragment(PlatformConfiguration.class));
 
@@ -149,7 +148,7 @@
   /** Returns a map from the requested toolchain type to the {@link ToolchainTypeInfo} provider. */
   private static ImmutableMap<Label, ToolchainTypeInfo> loadToolchainTypes(
       Environment environment,
-      BuildConfiguration configuration,
+      BuildConfigurationValue configuration,
       ImmutableSet<Label> requestedToolchainTypeLabels)
       throws InvalidToolchainTypeException, InterruptedException, ValueMissingException {
     ImmutableSet<ConfiguredTargetKey> toolchainTypeKeys =
@@ -208,8 +207,8 @@
   private static PlatformKeys loadPlatformKeys(
       SkyFunction.Environment environment,
       boolean debug,
-      BuildConfigurationValue.Key configurationKey,
-      BuildConfiguration configuration,
+      BuildConfigurationKey configurationKey,
+      BuildConfigurationValue configuration,
       PlatformConfiguration platformConfiguration,
       ImmutableSet<Label> execConstraintLabels)
       throws InterruptedException, ValueMissingException, InvalidConstraintValueException,
@@ -251,8 +250,8 @@
   private static ImmutableList<ConfiguredTargetKey> loadExecutionPlatformKeys(
       SkyFunction.Environment environment,
       boolean debug,
-      BuildConfigurationValue.Key configurationKey,
-      BuildConfiguration configuration,
+      BuildConfigurationKey configurationKey,
+      BuildConfigurationValue configuration,
       ConfiguredTargetKey defaultPlatformKey,
       ImmutableSet<Label> execConstraintLabels)
       throws InterruptedException, ValueMissingException, InvalidConstraintValueException,
@@ -352,7 +351,7 @@
 
   private static void determineToolchainImplementations(
       Environment environment,
-      BuildConfigurationValue.Key configurationKey,
+      BuildConfigurationKey configurationKey,
       ImmutableSet<Label> requiredToolchainTypeLabels,
       Optional<ConfiguredTargetKey> forcedExecutionPlatform,
       UnloadedToolchainContextImpl.Builder builder,
@@ -428,7 +427,7 @@
             platformKeys.executionPlatformKeys(),
             resolvedToolchains);
 
-    if (!selectedExecutionPlatformKey.isPresent()) {
+    if (selectedExecutionPlatformKey.isEmpty()) {
       throw new NoMatchingPlatformException(
           requiredToolchainTypeLabels,
           platformKeys.executionPlatformKeys(),