diff --git a/src/Configurator/CopyFromRecipeConfigurator.php b/src/Configurator/CopyFromRecipeConfigurator.php
index 7a99a6dfc..47a360ea1 100644
--- a/src/Configurator/CopyFromRecipeConfigurator.php
+++ b/src/Configurator/CopyFromRecipeConfigurator.php
@@ -37,18 +37,35 @@ public function unconfigure(Recipe $recipe, $config, Lock $lock)
     public function update(RecipeUpdate $recipeUpdate, array $originalConfig, array $newConfig): void
     {
         foreach ($recipeUpdate->getOriginalRecipe()->getFiles() as $filename => $data) {
+            $filename = $this->resolveTargetFolder($filename, $originalConfig);
             $recipeUpdate->setOriginalFile($filename, $data['contents']);
         }
 
         $files = [];
         foreach ($recipeUpdate->getNewRecipe()->getFiles() as $filename => $data) {
+            $filename = $this->resolveTargetFolder($filename, $newConfig);
             $recipeUpdate->setNewFile($filename, $data['contents']);
 
             $files[] = $this->getLocalFilePath($recipeUpdate->getRootDir(), $filename);
         }
+
         $recipeUpdate->getLock()->add($recipeUpdate->getPackageName(), ['files' => $files]);
     }
 
+    /**
+     * @param array<string, string> $config
+     */
+    private function resolveTargetFolder(string $path, array $config): string
+    {
+        foreach ($config as $key => $target) {
+            if (0 === strpos($path, $key)) {
+                return $this->options->expandTargetDir($target).substr($path, \strlen($key));
+            }
+        }
+
+        return $path;
+    }
+
     private function getRemovableFilesFromRecipeAndLock(Recipe $recipe, Lock $lock): array
     {
         $lockedFiles = array_unique(
diff --git a/tests/Command/UpdateRecipesCommandTest.php b/tests/Command/UpdateRecipesCommandTest.php
index 1f09cf9ef..efd16f547 100644
--- a/tests/Command/UpdateRecipesCommandTest.php
+++ b/tests/Command/UpdateRecipesCommandTest.php
@@ -100,7 +100,7 @@ private function createCommandUpdateRecipes(): CommandTester
             $rfs = Factory::createRemoteFilesystem($this->io, $composer->getConfig());
             $rfs = new ParallelDownloader($this->io, $composer->getConfig(), $rfs->getOptions(), $rfs->isTlsDisabled());
         }
-        $options = new Options(['root-dir' => FLEX_TEST_DIR]);
+        $options = new Options(['root-dir' => FLEX_TEST_DIR, 'bin-dir' => 'bin/']);
         $command = new UpdateRecipesCommand(
             $flex,
             new Downloader($composer, $this->io, $rfs),
diff --git a/tests/Configurator/CopyFromRecipeConfiguratorTest.php b/tests/Configurator/CopyFromRecipeConfiguratorTest.php
index b0e943612..95f016567 100644
--- a/tests/Configurator/CopyFromRecipeConfiguratorTest.php
+++ b/tests/Configurator/CopyFromRecipeConfiguratorTest.php
@@ -190,6 +190,84 @@ public function testUpdate()
         $this->assertSame($newRecipeFiles, $recipeUpdate->getNewFiles());
     }
 
+    public function testUpdateResolveDirectories()
+    {
+        $configurator = $this->createConfigurator();
+
+        $lock = $this->createMock(Lock::class);
+        $lock->expects($this->once())
+            ->method('add')
+            ->with(
+                'test-package',
+                [
+                    'files' => [
+                        'config/packages/framework.yaml',
+                        'test.yaml',
+                    ],
+                ]
+            );
+
+        $originalRecipeFiles = [
+            'symfony8config/packages/framework.yaml' => 'before',
+            'root/test.yaml' => 'before',
+        ];
+        $newRecipeFiles = [
+            'symfony8config/packages/framework.yaml' => 'after',
+            'root/test.yaml' => 'after',
+        ];
+
+        $originalRecipeFileData = [];
+        foreach ($originalRecipeFiles as $file => $contents) {
+            $originalRecipeFileData[$file] = ['contents' => $contents, 'executable' => false];
+        }
+
+        $newRecipeFileData = [];
+        foreach ($newRecipeFiles as $file => $contents) {
+            $newRecipeFileData[$file] = ['contents' => $contents, 'executable' => false];
+        }
+
+        $originalRecipe = $this->createMock(Recipe::class);
+        $originalRecipe->method('getName')
+            ->willReturn('test-package');
+        $originalRecipe->method('getFiles')
+            ->willReturn($originalRecipeFileData);
+
+        $newRecipe = $this->createMock(Recipe::class);
+        $newRecipe->method('getFiles')
+            ->willReturn($newRecipeFileData);
+
+        $recipeUpdate = new RecipeUpdate(
+            $originalRecipe,
+            $newRecipe,
+            $lock,
+            FLEX_TEST_DIR
+        );
+
+        $configurator->update(
+            $recipeUpdate,
+            [
+                'root/' => '',
+                'symfony8config/' => '%CONFIG_DIR%/',
+            ],
+            [
+                'root/' => '',
+                'symfony8config/' => '%CONFIG_DIR%/',
+            ]
+        );
+
+        // Due to root/ => '', we expect that root/ has been stripped
+        $this->assertArrayHasKey('test.yaml', $recipeUpdate->getOriginalFiles());
+        $this->assertArrayHasKey('test.yaml', $recipeUpdate->getNewFiles());
+
+        $this->assertSame('after', $recipeUpdate->getNewFiles()['test.yaml']);
+
+        // %CONFIG-DIR%, got resolved to config/packages back
+        $this->assertArrayHasKey('config/packages/framework.yaml', $recipeUpdate->getOriginalFiles());
+        $this->assertArrayHasKey('config/packages/framework.yaml', $recipeUpdate->getNewFiles());
+
+        $this->assertSame('after', $recipeUpdate->getNewFiles()['config/packages/framework.yaml']);
+    }
+
     protected function setUp(): void
     {
         parent::setUp();
@@ -223,7 +301,7 @@ protected function tearDown(): void
 
     private function createConfigurator(): CopyFromRecipeConfigurator
     {
-        return new CopyFromRecipeConfigurator($this->getMockBuilder(Composer::class)->getMock(), $this->io, new Options(['root-dir' => FLEX_TEST_DIR], $this->io));
+        return new CopyFromRecipeConfigurator($this->getMockBuilder(Composer::class)->getMock(), $this->io, new Options(['root-dir' => FLEX_TEST_DIR, 'config-dir' => 'config'], $this->io));
     }
 
     private function cleanUpTargetFiles()
diff --git a/tests/FlexTest.php b/tests/FlexTest.php
index f4a315baa..b000c4451 100644
--- a/tests/FlexTest.php
+++ b/tests/FlexTest.php
@@ -322,7 +322,7 @@ public function testInstallWithPackageJsonToSynchronizeSkipped()
 
         $this->assertStringContainsString(
             'Skip synchronizing package.json with PHP packages',
-            $io->getOutput(),
+            $io->getOutput()
         );
     }
 
@@ -339,7 +339,7 @@ public function testInstallWithoutPackageJsonToSynchronizeSkipped(array $extra)
 
         $this->assertStringNotContainsString(
             'Skip synchronizing package.json with PHP packages',
-            $io->getOutput(),
+            $io->getOutput()
         );
     }