diff --git a/core/lib/Drupal/Core/Recipe/RecipeRunner.php b/core/lib/Drupal/Core/Recipe/RecipeRunner.php
index 4310a742ab04c9a03e5b3e430675f2479d848e29..9c00b0e363c02cec5790901892cf1386e1b8efd3 100644
--- a/core/lib/Drupal/Core/Recipe/RecipeRunner.php
+++ b/core/lib/Drupal/Core/Recipe/RecipeRunner.php
@@ -4,6 +4,8 @@
 
 namespace Drupal\Core\Recipe;
 
+use Drupal\Core\Config\Action\ConfigActionException;
+use Drupal\Core\Config\ConfigManagerInterface;
 use Drupal\Core\Config\FileStorage;
 use Drupal\Core\Config\InstallStorage;
 use Drupal\Core\Config\StorageInterface;
@@ -93,11 +95,14 @@ protected static function processInstall(InstallConfigurator $install, StorageIn
    *   The recipe being applied.
    */
   protected static function processConfiguration(Recipe $recipe): void {
+    /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
+    $config_manager = \Drupal::service(ConfigManagerInterface::class);
+
     $config_installer = new RecipeConfigInstaller(
       \Drupal::service('config.factory'),
       \Drupal::service('config.storage'),
       \Drupal::service('config.typed'),
-      \Drupal::service('config.manager'),
+      $config_manager,
       \Drupal::service('event_dispatcher'),
       NULL,
       \Drupal::service('extension.path.resolver'));
@@ -118,6 +123,13 @@ protected static function processConfiguration(Recipe $recipe): void {
       /** @var \Drupal\Core\Config\Action\ConfigActionManager $config_action_manager */
       $config_action_manager = \Drupal::service('plugin.manager.config_action');
       foreach ($config->config['actions'] as $config_name => $actions) {
+        // If this config name contains an input value, it must begin with the
+        // config prefix of a known entity type.
+        if (str_contains($config_name, '${') && empty($config_manager->getEntityTypeIdByName($config_name))) {
+          throw new ConfigActionException("The entity type for the config name '$config_name' could not be identified.");
+        }
+        $config_name = str_replace($keys, $replace, $config_name);
+
         foreach ($actions as $action_id => $data) {
           $config_action_manager->applyAction($action_id, $config_name, static::replaceInputValues($data, $replace));
         }
diff --git a/core/tests/Drupal/KernelTests/Core/Recipe/InputTest.php b/core/tests/Drupal/KernelTests/Core/Recipe/InputTest.php
index cc60172a9605ff5279abc7c29d34c5650416b961..cd3f14644e9ea7a1bfa7de1dcc767c3ac8483b9f 100644
--- a/core/tests/Drupal/KernelTests/Core/Recipe/InputTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Recipe/InputTest.php
@@ -6,6 +6,7 @@
 
 use Drupal\Component\Uuid\UuidInterface;
 use Drupal\contact\Entity\ContactForm;
+use Drupal\Core\Config\Action\ConfigActionException;
 use Drupal\Core\Recipe\ConsoleInputCollector;
 use Drupal\Core\Recipe\InputCollectorInterface;
 use Drupal\Core\Recipe\Recipe;
@@ -14,6 +15,7 @@
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\FunctionalTests\Core\Recipe\RecipeTestTrait;
 use Drupal\KernelTests\KernelTestBase;
+use Drupal\node\Entity\NodeType;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Style\StyleInterface;
 use Symfony\Component\Validator\Exception\ValidationFailedException;
@@ -229,4 +231,45 @@ public function testLiterals(): void {
     $this->assertSame('int is 1234, bool is  and float is 3.141', $config->get('slogan'));
   }
 
+  /**
+   * Tests using input values in entity IDs for config actions.
+   */
+  public function testInputInConfigEntityIds(): void {
+    $this->assertFalse(\Drupal::moduleHandler()->moduleExists('node'));
+
+    $collector = new class () implements InputCollectorInterface {
+
+      /**
+       * {@inheritdoc}
+       */
+      public function collectValue(string $name, DataDefinitionInterface $definition, mixed $default_value): mixed {
+        return $default_value;
+      }
+
+    };
+    $recipe = Recipe::createFromDirectory('core/tests/fixtures/recipes/input_test');
+    $recipe->input->collectAll($collector);
+    RecipeRunner::processRecipe($recipe);
+    $this->assertInstanceOf(NodeType::class, NodeType::load('test'));
+
+    // Using an input placeholder in a non-identifying part of the config entity
+    // ID should cause an exception.
+    $recipe = $this->createRecipe([
+      'name' => 'Invalid use of an input in config entity ID',
+      'config' => [
+        'actions' => [
+          'node.${anything}.test' => [
+            'createIfNotExists' => [
+              'id' => 'test',
+            ],
+          ],
+        ],
+      ],
+    ]);
+    $recipe->input->collectAll($collector);
+    $this->expectException(ConfigActionException::class);
+    $this->expectExceptionMessage("The entity type for the config name 'node.\${anything}.test' could not be identified.");
+    RecipeRunner::processRecipe($recipe);
+  }
+
 }
diff --git a/core/tests/fixtures/recipes/input_test/recipe.yml b/core/tests/fixtures/recipes/input_test/recipe.yml
index 279bc7fee4522e2d5114de55bd4c65e68258f090..7e8964429a72b4f589ae93830ff8459b4a12e675 100644
--- a/core/tests/fixtures/recipes/input_test/recipe.yml
+++ b/core/tests/fixtures/recipes/input_test/recipe.yml
@@ -3,6 +3,8 @@ recipes:
   # Depend on another recipe in order to prove that we can collect input
   # from recipes that depend on other recipes.
   - no_extensions
+install:
+  - node
 input:
   owner:
     data_type: string
@@ -27,8 +29,17 @@ input:
     default:
       source: value
       value: false
+  node_type:
+    data_type: string
+    description: 'The ID of a node type to create'
+    default:
+      source: value
+      value: 'test'
 config:
   actions:
+    node.type.${node_type}:
+      createIfNotExists:
+        name: Test Content Type
     system.site:
       simpleConfigUpdate:
         name: "${owner}'s Turf"