diff --git a/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/SetProperties.php b/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/SetProperties.php
new file mode 100644
index 0000000000000000000000000000000000000000..0ec3c7fc3253aa06d86f5728bb9fbfb467292741
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/SetProperties.php
@@ -0,0 +1,80 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Core\Config\Action\Plugin\ConfigAction;
+
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Config\Action\Attribute\ConfigAction;
+use Drupal\Core\Config\Action\ConfigActionException;
+use Drupal\Core\Config\Action\ConfigActionPluginInterface;
+use Drupal\Core\Config\ConfigManagerInterface;
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * @internal
+ *   This API is experimental.
+ */
+#[ConfigAction(
+  id: 'setProperties',
+  admin_label: new TranslatableMarkup('Set property of a config entity'),
+  entity_types: ['*'],
+)]
+final class SetProperties implements ConfigActionPluginInterface, ContainerFactoryPluginInterface {
+
+  public function __construct(
+    private readonly ConfigManagerInterface $configManager,
+  ) {}
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $container->get(ConfigManagerInterface::class),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function apply(string $configName, mixed $values): void {
+    $entity = $this->configManager->loadConfigEntityByName($configName);
+    assert($entity instanceof ConfigEntityInterface);
+
+    assert(is_array($values));
+    assert(!array_is_list($values));
+
+    // Don't allow the ID or UUID to be changed.
+    $entity_keys = $entity->getEntityType()->getKeys();
+    $forbidden_keys = array_filter([
+      $entity_keys['id'],
+      $entity_keys['uuid'],
+    ]);
+
+    foreach ($values as $property_name => $value) {
+      if (in_array($property_name, $forbidden_keys, TRUE)) {
+        throw new ConfigActionException("Entity key '$property_name' cannot be changed by the setProperties config action.");
+      }
+      $parts = explode('.', $property_name);
+
+      $property_value = $entity->get($parts[0]);
+      if (count($parts) > 1) {
+        if (isset($property_value) && !is_array($property_value)) {
+          throw new ConfigActionException('The setProperties config action can only set nested values on arrays.');
+        }
+        $property_value ??= [];
+        NestedArray::setValue($property_value, array_slice($parts, 1), $value);
+      }
+      else {
+        $property_value = $value;
+      }
+      $entity->set($parts[0], $property_value);
+    }
+    $entity->save();
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/SimpleConfigUpdate.php b/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/SimpleConfigUpdate.php
index 2e9064f3a3fc75be4183b1e64ffb0589dee41f82..8df05ae91c4df895fe65aae52d7f142a70abeb93 100644
--- a/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/SimpleConfigUpdate.php
+++ b/core/lib/Drupal/Core/Config/Action/Plugin/ConfigAction/SimpleConfigUpdate.php
@@ -8,6 +8,7 @@
 use Drupal\Core\Config\Action\ConfigActionException;
 use Drupal\Core\Config\Action\ConfigActionPluginInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Config\ConfigManagerInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -22,31 +23,31 @@
 )]
 final class SimpleConfigUpdate implements ConfigActionPluginInterface, ContainerFactoryPluginInterface {
 
-  /**
-   * Constructs a SimpleConfigUpdate object.
-   *
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
-   *   The config factory.
-   */
   public function __construct(
-    protected readonly ConfigFactoryInterface $configFactory,
-  ) {
-  }
+    private readonly ConfigFactoryInterface $configFactory,
+    private readonly ConfigManagerInterface $configManager,
+  ) {}
 
   /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
-    return new static($container->get('config.factory'));
+    return new static(
+      $container->get(ConfigFactoryInterface::class),
+      $container->get(ConfigManagerInterface::class),
+    );
   }
 
   /**
    * {@inheritdoc}
    */
   public function apply(string $configName, mixed $value): void {
+    if ($this->configManager->getEntityTypeIdByName($configName)) {
+      // @todo Make this an exception in https://www.drupal.org/node/3515544.
+      @trigger_error('Using the simpleConfigUpdate config action on config entities is deprecated in drupal:11.2.0 and throws an exception in drupal:12.0.0. Use the setProperties action instead. See https://www.drupal.org/node/3515543', E_USER_DEPRECATED);
+    }
+
     $config = $this->configFactory->getEditable($configName);
-    // @todo https://www.drupal.org/i/3439713 Should we error if this is a
-    //   config entity?
     if ($config->isNew()) {
       throw new ConfigActionException(sprintf('Config %s does not exist so can not be updated', $configName));
     }
diff --git a/core/tests/Drupal/KernelTests/Core/Recipe/ConfigActionValidationTest.php b/core/tests/Drupal/KernelTests/Core/Recipe/ConfigActionValidationTest.php
index e5df2b824b19f558da601441790e733a18b93b0e..871e0775777033fb52b7088a6a739ed6cf6e97ec 100644
--- a/core/tests/Drupal/KernelTests/Core/Recipe/ConfigActionValidationTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Recipe/ConfigActionValidationTest.php
@@ -77,7 +77,7 @@ public function testConfigActionsAreValidated(string $entity_type_id): void {
 config:
   actions:
     $config_name:
-      simpleConfigUpdate:
+      setProperties:
         $label_key: ''
 YAML;
 
diff --git a/core/tests/Drupal/KernelTests/Core/Recipe/EntityMethodConfigActionsTest.php b/core/tests/Drupal/KernelTests/Core/Recipe/EntityMethodConfigActionsTest.php
index 8c08c3b8c848adde724af93690dd3202705f8189..f1ae746ddd025389d1e50bacf2a0e8b2d275730c 100644
--- a/core/tests/Drupal/KernelTests/Core/Recipe/EntityMethodConfigActionsTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Recipe/EntityMethodConfigActionsTest.php
@@ -4,21 +4,27 @@
 
 namespace Drupal\KernelTests\Core\Recipe;
 
+use Drupal\block\Entity\Block;
+use Drupal\Core\Config\Action\ConfigActionException;
 use Drupal\Core\Config\Action\ConfigActionManager;
 use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Extension\ThemeInstallerInterface;
 use Drupal\entity_test\Entity\EntityTestBundle;
 use Drupal\KernelTests\KernelTestBase;
+use Drupal\Tests\block\Traits\BlockCreationTrait;
 
 /**
  * @group Recipe
  */
 class EntityMethodConfigActionsTest extends KernelTestBase {
 
+  use BlockCreationTrait;
+
   /**
    * {@inheritdoc}
    */
-  protected static $modules = ['config_test', 'entity_test', 'system'];
+  protected static $modules = ['block', 'config_test', 'entity_test', 'system'];
 
   /**
    * The configuration action manager.
@@ -172,4 +178,90 @@ public function testRemoveComponentFromDisplay(string $action_name): void {
     $this->assertFalse($this->configActionManager->hasDefinition($plugin_id));
   }
 
+  /**
+   * Test setting a nested property on a config entity.
+   */
+  public function testSetNestedProperty(): void {
+    $this->container->get(ThemeInstallerInterface::class)
+      ->install(['claro']);
+    $block = $this->placeBlock('local_tasks_block', ['theme' => 'claro']);
+
+    $this->configActionManager->applyAction(
+      'setProperties',
+      $block->getConfigDependencyName(),
+      ['settings.label' => 'Magic!'],
+    );
+    $settings = Block::load($block->id())->get('settings');
+    $this->assertSame('Magic!', $settings['label']);
+
+    // If the property is not nested, it should still work.
+    $settings['label'] = 'Mundane';
+    $this->configActionManager->applyAction(
+      'setProperties',
+      $block->getConfigDependencyName(),
+      ['settings' => $settings],
+    );
+    $settings = Block::load($block->id())->get('settings');
+    $this->assertSame('Mundane', $settings['label']);
+
+    // We can use this to set a scalar property normally.
+    $this->configActionManager->applyAction(
+      'setProperties',
+      $block->getConfigDependencyName(),
+      ['region' => 'highlighted'],
+    );
+    $this->assertSame('highlighted', Block::load($block->id())->getRegion());
+
+    // We should get an exception if we try to set a nested value on a property
+    // that isn't an array.
+    $this->expectException(ConfigActionException::class);
+    $this->expectExceptionMessage('The setProperties config action can only set nested values on arrays.');
+    $this->configActionManager->applyAction(
+      'setProperties',
+      $block->getConfigDependencyName(),
+      ['theme.name' => 'stark'],
+    );
+  }
+
+  /**
+   * Tests that the setProperties action refuses to modify entity IDs or UUIDs.
+   *
+   * @testWith ["id"]
+   *   ["uuid"]
+   */
+  public function testSetPropertiesWillNotChangeEntityKeys(string $key): void {
+    $view_display = $this->container->get(EntityDisplayRepositoryInterface::class)
+      ->getViewDisplay('entity_test_with_bundle', 'test');
+    $this->assertFalse($view_display->isNew());
+
+    $property_name = $view_display->getEntityType()->getKey($key);
+    $this->assertNotEmpty($property_name);
+
+    $this->expectException(ConfigActionException::class);
+    $this->expectExceptionMessage("Entity key '$property_name' cannot be changed by the setProperties config action.");
+    $this->configActionManager->applyAction(
+      'setProperties',
+      $view_display->getConfigDependencyName(),
+      [$property_name => '12345'],
+    );
+  }
+
+  /**
+   * Tests that the simpleConfigUpdate action cannot be used on entities.
+   *
+   * @group legacy
+   */
+  public function testSimpleConfigUpdateFailsOnEntities(): void {
+    $view_display = $this->container->get(EntityDisplayRepositoryInterface::class)
+      ->getViewDisplay('entity_test_with_bundle', 'test');
+    $view_display->save();
+
+    $this->expectDeprecation('Using the simpleConfigUpdate config action on config entities is deprecated in drupal:11.2.0 and throws an exception in drupal:12.0.0. Use the setProperties action instead. See https://www.drupal.org/node/3515543');
+    $this->configActionManager->applyAction(
+      'simpleConfigUpdate',
+      $view_display->getConfigDependencyName(),
+      ['hidden.uid' => TRUE],
+    );
+  }
+
 }