You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by gn...@apache.org on 2026/08/27 13:01:57 UTC

(camel) branch main updated: CAMEL-24463: Introduce KeyValueRepository SPI + adapt state-store component

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 1d70c58d6269 CAMEL-24463: Introduce KeyValueRepository SPI + adapt state-store component
1d70c58d6269 is described below

commit 1d70c58d62692723cc0aed88ac69869c9445f0be
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Thu Aug 27 15:01:50 2026 +0200

    CAMEL-24463: Introduce KeyValueRepository SPI + adapt state-store component
    
    Introduces a unified KeyValueRepository SPI in camel-api with:
    - MemoryKeyValueRepository (ConcurrentHashMap + lazy TTL)
    - KeyValueIdempotentRepository adapter (idempotent: prefix)
    - KeyValueAggregationRepository adapter (aggregate: prefix)
    - Auto-discovery from registry for Aggregator and IdempotentConsumer EIPs
    - State-store component adapted to use KeyValueRepository directly
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
---
 bom/camel-bom/pom.xml                              |  15 --
 catalog/camel-allcomponents/pom.xml                |  15 --
 .../org/apache/camel/catalog/beans.properties      |   1 +
 .../catalog/beans/MemoryKeyValueRepository.json    |  15 ++
 .../camel/catalog/components/state-store.json      |   4 +-
 .../camel/catalog/docs/state-store-component.adoc  | 271 ++++-----------------
 .../org/apache/camel/catalog/others.properties     |   3 -
 .../camel/catalog/others/state-store-caffeine.json |  14 --
 .../catalog/others/state-store-infinispan.json     |  14 --
 .../camel/catalog/others/state-store-redis.json    |  14 --
 .../camel-state-store-caffeine/pom.xml             |  64 -----
 .../services/org/apache/camel/other.properties     |   7 -
 .../generated/resources/state-store-caffeine.json  |  14 --
 .../caffeine/CaffeineStateStoreBackend.java        | 133 ----------
 .../caffeine/CaffeineStateStoreBackendTest.java    | 198 ---------------
 .../caffeine/CaffeineStateStorePropertiesTest.java |  95 --------
 .../camel-state-store-infinispan/pom.xml           |  71 ------
 .../services/org/apache/camel/other.properties     |   7 -
 .../resources/state-store-infinispan.json          |  14 --
 .../infinispan/InfinispanStateStoreBackend.java    | 135 ----------
 .../infinispan/InfinispanStateStoreBackendIT.java  | 240 ------------------
 .../InfinispanStateStorePropertiesIT.java          | 133 ----------
 .../camel-state-store-redis/pom.xml                |  71 ------
 .../services/org/apache/camel/other.properties     |   7 -
 .../src/generated/resources/state-store-redis.json |  14 --
 .../statestore/redis/RedisStateStoreBackend.java   | 132 ----------
 .../statestore/redis/RedisStateStoreBackendIT.java | 204 ----------------
 .../redis/RedisStateStorePropertiesIT.java         |  83 -------
 .../statestore/StateStoreEndpointConfigurer.java   |   4 +-
 .../camel/component/statestore/state-store.json    |   4 +-
 .../src/main/docs/state-store-component.adoc       | 271 ++++-----------------
 .../statestore/InMemoryStateStoreBackend.java      | 128 ----------
 .../component/statestore/StateStoreBackend.java    | 103 --------
 .../component/statestore/StateStoreComponent.java  |  35 +--
 .../component/statestore/StateStoreEndpoint.java   |  11 +-
 .../component/statestore/StateStoreProducer.java   |   5 +-
 .../statestore/StateStoreAutoDiscoveryTest.java    |  16 +-
 .../StateStoreMultiBackendFallbackTest.java        |  12 +-
 components/camel-state-store/pom.xml               |   3 -
 .../org/apache/camel/spi/KeyValueRepository.java   | 121 +++++++++
 .../processor/aggregate/AggregateProcessor.java    |  13 +-
 .../camel/reifier/IdempotentConsumerReifier.java   |  22 +-
 .../support/KeyValueAggregationRepositoryTest.java | 214 ++++++++++++++++
 core/camel-support/pom.xml                         |  11 +
 .../MemoryKeyValueRepositoryConfigurer.java        |  37 +++
 .../services/org/apache/camel/bean.properties      |   2 +-
 .../camel/bean/MemoryKeyValueRepository.json       |  15 ++
 ...g.apache.camel.support.MemoryKeyValueRepository |   2 +
 .../support/KeyValueAggregationRepository.java     | 238 ++++++++++++++++++
 .../support/KeyValueIdempotentRepository.java      | 114 +++++++++
 .../camel/support/MemoryKeyValueRepository.java    | 198 +++++++++++++++
 .../support/KeyValueIdempotentRepositoryTest.java  | 178 ++++++++++++++
 .../support/MemoryKeyValueRepositoryTest.java      | 227 +++++++++++++++++
 .../others/examples/json/state-store-caffeine.json |   1 -
 .../examples/json/state-store-infinispan.json      |   1 -
 .../others/examples/json/state-store-redis.json    |   1 -
 .../component/ComponentsBuilderFactory.java        |   3 +-
 .../dsl/StateStoreComponentBuilderFactory.java     |   5 +-
 .../builder/endpoint/EndpointHeaderBuilders.java   |   3 +-
 .../builder/endpoint/StaticEndpointBuilders.java   |   6 +-
 .../dsl/StateStoreEndpointBuilderFactory.java      |  23 +-
 parent/pom.xml                                     |  15 --
 62 files changed, 1560 insertions(+), 2470 deletions(-)

diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index d70d54289386..d1a957d68568 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -2327,21 +2327,6 @@
         <artifactId>camel-state-store</artifactId>
         <version>4.23.0-SNAPSHOT</version>
       </dependency>
-      <dependency>
-        <groupId>org.apache.camel</groupId>
-        <artifactId>camel-state-store-caffeine</artifactId>
-        <version>4.23.0-SNAPSHOT</version>
-      </dependency>
-      <dependency>
-        <groupId>org.apache.camel</groupId>
-        <artifactId>camel-state-store-infinispan</artifactId>
-        <version>4.23.0-SNAPSHOT</version>
-      </dependency>
-      <dependency>
-        <groupId>org.apache.camel</groupId>
-        <artifactId>camel-state-store-redis</artifactId>
-        <version>4.23.0-SNAPSHOT</version>
-      </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
         <artifactId>camel-stax</artifactId>
diff --git a/catalog/camel-allcomponents/pom.xml b/catalog/camel-allcomponents/pom.xml
index 6fe7977a95a1..9a6aad45c5a1 100644
--- a/catalog/camel-allcomponents/pom.xml
+++ b/catalog/camel-allcomponents/pom.xml
@@ -2107,21 +2107,6 @@
             <artifactId>camel-state-store</artifactId>
             <version>${project.version}</version>
         </dependency>
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-state-store-caffeine</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-state-store-infinispan</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-state-store-redis</artifactId>
-            <version>${project.version}</version>
-        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-stax</artifactId>
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans.properties
index a3b23ef4988e..d355b8bfd5e8 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans.properties
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans.properties
@@ -34,6 +34,7 @@ KubernetesClusterService
 LoggingHttpActivityListener
 MemoryAggregationRepository
 MemoryIdempotentRepository
+MemoryKeyValueRepository
 MongoDbIdempotentRepository
 OpensearchBulkRequestAggregationStrategy
 RedisAggregationRepository
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans/MemoryKeyValueRepository.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans/MemoryKeyValueRepository.json
new file mode 100644
index 000000000000..4630dec20634
--- /dev/null
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/beans/MemoryKeyValueRepository.json
@@ -0,0 +1,15 @@
+{
+  "bean": {
+    "kind": "bean",
+    "name": "MemoryKeyValueRepository",
+    "javaType": "org.apache.camel.support.MemoryKeyValueRepository",
+    "interfaceType": "org.apache.camel.spi.KeyValueRepository",
+    "title": "Memory Key Value Repository",
+    "description": "An in-memory KeyValueRepository with optional TTL support.",
+    "deprecated": false,
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-support",
+    "version": "4.23.0-SNAPSHOT"
+  }
+}
+
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/state-store.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/state-store.json
index d90c315d879c..470d0b127426 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/state-store.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/state-store.json
@@ -3,7 +3,7 @@
     "kind": "component",
     "name": "state-store",
     "title": "State Store",
-    "description": "Perform key-value operations against a pluggable state store backend.",
+    "description": "Perform key-value operations against a pluggable KeyValueRepository backend.",
     "deprecated": false,
     "firstVersion": "4.23.0",
     "label": "cache",
@@ -37,6 +37,6 @@
     "operation": { "index": 1, "kind": "parameter", "displayName": "Operation", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "org.apache.camel.component.statestore.StateStoreOperations", "enum": [ "put", "putIfAbsent", "get", "delete", "contains", "keys", "size", "clear" ], "deprecated": false, "autowired": false, "secret": false, "description": "The default operation to perform" },
     "ttl": { "index": 2, "kind": "parameter", "displayName": "Ttl", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 0, "description": "Time-to-live in milliseconds for entries. 0 means no expiry." },
     "lazyStartProducer": { "index": 3, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produc [...]
-    "backend": { "index": 4, "kind": "parameter", "displayName": "Backend", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.statestore.StateStoreBackend", "deprecated": false, "autowired": false, "secret": false, "description": "The backend to use. If not set, auto-discovers a single StateStoreBackend from the registry, or falls back to an in-memory store." }
+    "backend": { "index": 4, "kind": "parameter", "displayName": "Backend", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.KeyValueRepository", "deprecated": false, "autowired": false, "secret": false, "description": "The backend to use. If not set, auto-discovers a single KeyValueRepository from the registry, or falls back to an in-memory store." }
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/state-store-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/state-store-component.adoc
index c37fb9acaf18..e110ccc0bca5 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/state-store-component.adoc
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/state-store-component.adoc
@@ -2,7 +2,7 @@
 :doctitle: State Store
 :shortname: state-store
 :artifactid: camel-state-store
-:description: Perform key-value operations against a pluggable state store backend.
+:description: Perform key-value operations against a pluggable KeyValueRepository backend.
 :since: 4.23
 :supportlevel: Preview
 :tabs-sync-option:
@@ -12,13 +12,14 @@
 
 *{component-header}*
 
-The State Store component provides a simple, unified key-value store API with pluggable backends.
-It is useful for caching, session state, and scenarios where you need a simple object store
-(similar to MuleSoft's Object Store).
+The State Store component provides a simple, unified key-value store API backed by the
+`KeyValueRepository` SPI from `camel-api`. It is useful for caching, session state, and
+scenarios where you need a simple object store (similar to MuleSoft's Object Store).
 
-By default, an in-memory backend is used (based on `ConcurrentHashMap`), but you can plug in
-any custom backend by implementing the `StateStoreBackend` interface or using one of the
-provided backend modules:
+By default, an in-memory backend is used (`MemoryKeyValueRepository` from `camel-support`),
+but you can plug in any `KeyValueRepository` implementation. The same `KeyValueRepository`
+can also be used as the backend for the Idempotent Consumer and Aggregator EIPs via the
+`KeyValueIdempotentRepository` and `KeyValueAggregationRepository` adapters.
 
 == When to use State Store vs individual components
 
@@ -31,17 +32,9 @@ Use State Store when:
 
 * You need a *simple key-value API* and want to switch backends without changing route logic.
 * You are *migrating from MuleSoft* and want an Object Store equivalent.
-* You want *backend portability* — develop with in-memory, deploy with Redis or Infinispan.
-* Your use case is limited to *put, putIfAbsent, get, delete, contains, keys, size, clear* operations.
-
-[width="100%",cols="1,2,1",options="header"]
-|===
-| Backend | Module | Description
-| In-Memory | `camel-state-store` | Default. Uses `ConcurrentHashMap` with lazy TTL expiry. No external dependencies.
-| Caffeine | `camel-state-store-caffeine` | High-performance local cache with proper eviction and per-entry TTL.
-| Redis | `camel-state-store-redis` | Distributed store via Redisson. Supports per-entry TTL natively.
-| Infinispan | `camel-state-store-infinispan` | Distributed cache via Hot Rod client. Supports per-entry TTL via lifespan.
-|===
+* You want *backend portability* — develop with in-memory, deploy with any `KeyValueRepository`.
+* Your use case is limited to *put, get, delete, contains, keys* operations.
+* You want a *single backend* to serve state store, idempotent consumer, and aggregation patterns.
 
 == URI Format
 
@@ -164,226 +157,35 @@ from("direct:init")
 === Backend auto-discovery
 
 If no `backend` option is specified on the endpoint, the component automatically looks up a
-`StateStoreBackend` bean from the Camel registry. If exactly one is found, it is used for all
-endpoints. If none is found, the default in-memory backend is used.
+`KeyValueRepository` bean from the Camel registry. If exactly one is found, it is used for all
+endpoints. If none is found, the default in-memory backend (`MemoryKeyValueRepository`) is used.
 
 This means you can configure a backend once (via Java or properties) and all `state-store`
 endpoints will use it without needing `backend=#beanName` on each endpoint URI.
 
-=== Configuring backends via properties
-
-Backends can be configured entirely via `application.properties` using Camel's `camel.beans.*`
-syntax, without writing any Java code. This is especially useful for YAML DSL or Camel JBang users.
-
-[tabs]
-====
-Caffeine::
-+
-[source,properties]
-----
-# application.properties
-camel.beans.caffeineBackend = #class:org.apache.camel.component.statestore.caffeine.CaffeineStateStoreBackend
-camel.beans.caffeineBackend.maximumSize = 50000
-----
-
-Redis::
-+
-[source,properties]
-----
-# application.properties
-camel.beans.redisBackend = #class:org.apache.camel.component.statestore.redis.RedisStateStoreBackend
-camel.beans.redisBackend.redisUrl = redis://myhost:6379
-camel.beans.redisBackend.mapName = my-app-state
-----
-
-Infinispan::
-+
-[source,properties]
-----
-# application.properties
-camel.beans.infinispanBackend = #class:org.apache.camel.component.statestore.infinispan.InfinispanStateStoreBackend
-camel.beans.infinispanBackend.hosts = myhost:11222
-camel.beans.infinispanBackend.cacheName = my-cache
-----
-====
-
-With the backend configured via properties and auto-discovery, no `backend=#...` reference
-is needed in the route:
-
-[source,yaml]
-----
-- route:
-    from:
-      uri: direct:store
-    steps:
-      - setHeader:
-          name: CamelStateStoreKey
-          constant: myKey
-      - to:
-          uri: state-store:myStore?operation=put
-----
-
 === In-Memory (default)
 
-The default backend stores entries in a `ConcurrentHashMap`. TTL expiry is lazy -- entries are
-checked and removed on access rather than by a background thread.
+The default backend (`MemoryKeyValueRepository`) stores entries in a `ConcurrentHashMap`. TTL
+expiry is lazy -- entries are checked and removed on access rather than by a background thread.
 
 No additional dependency is needed beyond `camel-state-store`.
 
-=== Caffeine
-
-Add the dependency:
-
-[source,xml]
-----
-<dependency>
-    <groupId>org.apache.camel</groupId>
-    <artifactId>camel-state-store-caffeine</artifactId>
-</dependency>
-----
-
-[tabs]
-====
-Java::
-+
-[source,java]
-----
-@BindToRegistry("caffeineBackend")
-public CaffeineStateStoreBackend caffeine() {
-    CaffeineStateStoreBackend backend = new CaffeineStateStoreBackend();
-    backend.setMaximumSize(50_000); // default is 10,000
-    return backend;
-}
-----
-
-Properties::
-+
-[source,properties]
-----
-camel.beans.caffeineBackend = #class:org.apache.camel.component.statestore.caffeine.CaffeineStateStoreBackend
-camel.beans.caffeineBackend.maximumSize = 50000
-----
-====
-
-With auto-discovery, the backend is picked up automatically. You can also reference it explicitly:
-
-[source,java]
-----
-from("direct:store")
-    .to("state-store:myStore?operation=put&backend=#caffeineBackend");
-----
-
-Caffeine provides proper eviction policies and active TTL expiration using variable expiry.
-
-=== Redis
-
-Add the dependency:
-
-[source,xml]
-----
-<dependency>
-    <groupId>org.apache.camel</groupId>
-    <artifactId>camel-state-store-redis</artifactId>
-</dependency>
-----
-
-[tabs]
-====
-Java::
-+
-[source,java]
-----
-@BindToRegistry("redisBackend")
-public RedisStateStoreBackend redis() {
-    RedisStateStoreBackend backend = new RedisStateStoreBackend();
-    backend.setRedisUrl("redis://myhost:6379");
-    backend.setMapName("my-app-state"); // Redis map name
-    return backend;
-}
-----
-
-Properties::
-+
-[source,properties]
-----
-camel.beans.redisBackend = #class:org.apache.camel.component.statestore.redis.RedisStateStoreBackend
-camel.beans.redisBackend.redisUrl = redis://myhost:6379
-camel.beans.redisBackend.mapName = my-app-state
-----
-====
-
-You can also inject a pre-configured `RedissonClient`:
-
-[source,java]
-----
-backend.setRedisson(existingRedissonClient);
-----
-
-Redis provides native per-entry TTL via `RMapCache`. Data is distributed and persisted according
-to your Redis configuration.
-
-=== Infinispan
-
-Add the dependency:
-
-[source,xml]
-----
-<dependency>
-    <groupId>org.apache.camel</groupId>
-    <artifactId>camel-state-store-infinispan</artifactId>
-</dependency>
-----
-
-[tabs]
-====
-Java::
-+
-[source,java]
-----
-@BindToRegistry("infinispanBackend")
-public InfinispanStateStoreBackend infinispan() {
-    InfinispanStateStoreBackend backend = new InfinispanStateStoreBackend();
-    backend.setHosts("myhost:11222");
-    backend.setCacheName("my-cache");
-    return backend;
-}
-----
-
-Properties::
-+
-[source,properties]
-----
-camel.beans.infinispanBackend = #class:org.apache.camel.component.statestore.infinispan.InfinispanStateStoreBackend
-camel.beans.infinispanBackend.hosts = myhost:11222
-camel.beans.infinispanBackend.cacheName = my-cache
-----
-====
-
-You can also inject a pre-configured `RemoteCacheManager`:
-
-[source,java]
-----
-backend.setCacheManager(existingCacheManager);
-----
-
-Infinispan provides native per-entry TTL via the lifespan parameter and supports distributed caching.
-
 == Custom Backend
 
-Implement the `StateStoreBackend` interface to create your own backend:
+Implement the `KeyValueRepository` interface (from `org.apache.camel.spi`) to create your own backend:
 
 [source,java]
 ----
-public class MyCustomBackend implements StateStoreBackend {
+public class MyCustomBackend extends ServiceSupport implements KeyValueRepository {
 
     @Override
-    public Object put(String key, Object value, long ttlMillis) {
-        // store the value, return previous
+    public Object get(String key) {
+        // retrieve the value
     }
 
     @Override
-    public Object get(String key) {
-        // retrieve the value
+    public Object put(String key, Object value, long ttlMillis) {
+        // store the value; return the previous value or null
     }
 
     @Override
@@ -405,16 +207,6 @@ public class MyCustomBackend implements StateStoreBackend {
     public void clear() {
         // remove all entries
     }
-
-    @Override
-    public void start() {
-        // initialize connections
-    }
-
-    @Override
-    public void stop() {
-        // clean up resources
-    }
 }
 ----
 
@@ -428,3 +220,24 @@ Then reference it via bean or let auto-discovery find it:
 from("direct:store")
     .to("state-store:myStore?operation=put&backend=#myCustomBackend");
 ----
+
+=== Sharing a backend across patterns
+
+Because `KeyValueRepository` is the unified SPI, the same implementation can be reused as the
+backend for the Idempotent Consumer and Aggregator EIPs:
+
+[source,java]
+----
+@BindToRegistry("kvRepo")
+public KeyValueRepository kvRepo() {
+    return new MemoryKeyValueRepository();
+}
+----
+
+With a single `KeyValueRepository` in the registry:
+
+* The State Store component auto-discovers and uses it.
+* The Idempotent Consumer EIP auto-discovers and wraps it in a `KeyValueIdempotentRepository`.
+* The Aggregator EIP auto-discovers and wraps it in a `KeyValueAggregationRepository`.
+
+No explicit wiring is needed — all three patterns share the same backend.
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties
index d906c34686b7..a7fef8848b0d 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others.properties
@@ -57,9 +57,6 @@ spring-cloud-config
 spring-main
 spring-security
 spring-xml
-state-store-caffeine
-state-store-infinispan
-state-store-redis
 telemetry
 telemetry-dev
 test-junit5
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/state-store-caffeine.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/state-store-caffeine.json
deleted file mode 100644
index fc311aa76cb2..000000000000
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/state-store-caffeine.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "other": {
-    "kind": "other",
-    "name": "state-store-caffeine",
-    "title": "State Store Caffeine",
-    "description": "Camel State Store backend using Caffeine cache",
-    "deprecated": false,
-    "firstVersion": "4.23.0",
-    "supportLevel": "Preview",
-    "groupId": "org.apache.camel",
-    "artifactId": "camel-state-store-caffeine",
-    "version": "4.23.0-SNAPSHOT"
-  }
-}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/state-store-infinispan.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/state-store-infinispan.json
deleted file mode 100644
index a047688f0bcf..000000000000
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/state-store-infinispan.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "other": {
-    "kind": "other",
-    "name": "state-store-infinispan",
-    "title": "State Store Infinispan",
-    "description": "Camel State Store backend using Infinispan remote (Hot Rod)",
-    "deprecated": false,
-    "firstVersion": "4.23.0",
-    "supportLevel": "Preview",
-    "groupId": "org.apache.camel",
-    "artifactId": "camel-state-store-infinispan",
-    "version": "4.23.0-SNAPSHOT"
-  }
-}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/state-store-redis.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/state-store-redis.json
deleted file mode 100644
index 20889cda5326..000000000000
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/others/state-store-redis.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "other": {
-    "kind": "other",
-    "name": "state-store-redis",
-    "title": "State Store Redis",
-    "description": "Camel State Store backend using Redisson (Redis)",
-    "deprecated": false,
-    "firstVersion": "4.23.0",
-    "supportLevel": "Preview",
-    "groupId": "org.apache.camel",
-    "artifactId": "camel-state-store-redis",
-    "version": "4.23.0-SNAPSHOT"
-  }
-}
diff --git a/components/camel-state-store/camel-state-store-caffeine/pom.xml b/components/camel-state-store/camel-state-store-caffeine/pom.xml
deleted file mode 100644
index bed04dfb1a55..000000000000
--- a/components/camel-state-store/camel-state-store-caffeine/pom.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You 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.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.apache.camel</groupId>
-        <artifactId>camel-state-store-parent</artifactId>
-        <version>4.23.0-SNAPSHOT</version>
-    </parent>
-
-    <artifactId>camel-state-store-caffeine</artifactId>
-    <packaging>jar</packaging>
-
-    <name>Camel :: State Store :: Caffeine</name>
-    <description>Camel State Store backend using Caffeine cache</description>
-
-    <properties>
-        <firstVersion>4.23.0</firstVersion>
-    </properties>
-
-    <dependencies>
-
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-state-store</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>com.github.ben-manes.caffeine</groupId>
-            <artifactId>caffeine</artifactId>
-        </dependency>
-
-        <!-- testing -->
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-test-main-junit5</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.assertj</groupId>
-            <artifactId>assertj-core</artifactId>
-            <scope>test</scope>
-        </dependency>
-
-    </dependencies>
-</project>
diff --git a/components/camel-state-store/camel-state-store-caffeine/src/generated/resources/META-INF/services/org/apache/camel/other.properties b/components/camel-state-store/camel-state-store-caffeine/src/generated/resources/META-INF/services/org/apache/camel/other.properties
deleted file mode 100644
index f873d149c96f..000000000000
--- a/components/camel-state-store/camel-state-store-caffeine/src/generated/resources/META-INF/services/org/apache/camel/other.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-# Generated by camel build tools - do NOT edit this file!
-name=state-store-caffeine
-groupId=org.apache.camel
-artifactId=camel-state-store-caffeine
-version=4.23.0-SNAPSHOT
-projectName=Camel :: State Store :: Caffeine
-projectDescription=Camel State Store backend using Caffeine cache
diff --git a/components/camel-state-store/camel-state-store-caffeine/src/generated/resources/state-store-caffeine.json b/components/camel-state-store/camel-state-store-caffeine/src/generated/resources/state-store-caffeine.json
deleted file mode 100644
index fc311aa76cb2..000000000000
--- a/components/camel-state-store/camel-state-store-caffeine/src/generated/resources/state-store-caffeine.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "other": {
-    "kind": "other",
-    "name": "state-store-caffeine",
-    "title": "State Store Caffeine",
-    "description": "Camel State Store backend using Caffeine cache",
-    "deprecated": false,
-    "firstVersion": "4.23.0",
-    "supportLevel": "Preview",
-    "groupId": "org.apache.camel",
-    "artifactId": "camel-state-store-caffeine",
-    "version": "4.23.0-SNAPSHOT"
-  }
-}
diff --git a/components/camel-state-store/camel-state-store-caffeine/src/main/java/org/apache/camel/component/statestore/caffeine/CaffeineStateStoreBackend.java b/components/camel-state-store/camel-state-store-caffeine/src/main/java/org/apache/camel/component/statestore/caffeine/CaffeineStateStoreBackend.java
deleted file mode 100644
index 08a3316cd162..000000000000
--- a/components/camel-state-store/camel-state-store-caffeine/src/main/java/org/apache/camel/component/statestore/caffeine/CaffeineStateStoreBackend.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.camel.component.statestore.caffeine;
-
-import java.time.Duration;
-import java.util.Set;
-
-import com.github.benmanes.caffeine.cache.Cache;
-import com.github.benmanes.caffeine.cache.Caffeine;
-import com.github.benmanes.caffeine.cache.Expiry;
-import org.apache.camel.component.statestore.StateStoreBackend;
-
-/**
- * A {@link StateStoreBackend} implementation backed by Caffeine cache. Supports per-entry TTL using Caffeine's variable
- * expiration.
- *
- * @since 4.23
- */
-public class CaffeineStateStoreBackend implements StateStoreBackend {
-
-    private Cache<String, TimedValue> cache;
-    private int maximumSize = 10_000;
-
-    @Override
-    public Object put(String key, Object value, long ttlMillis) {
-        TimedValue previous = cache.asMap().put(key, new TimedValue(value, ttlMillis));
-        return previous != null ? previous.value() : null;
-    }
-
-    @Override
-    public Object get(String key) {
-        TimedValue entry = cache.getIfPresent(key);
-        return entry != null ? entry.value() : null;
-    }
-
-    @Override
-    public Object delete(String key) {
-        TimedValue previous = cache.asMap().remove(key);
-        return previous != null ? previous.value() : null;
-    }
-
-    @Override
-    public boolean contains(String key) {
-        return cache.getIfPresent(key) != null;
-    }
-
-    @Override
-    public Object putIfAbsent(String key, Object value, long ttlMillis) {
-        TimedValue newValue = new TimedValue(value, ttlMillis);
-        TimedValue existing = cache.asMap().putIfAbsent(key, newValue);
-        return existing != null ? existing.value() : null;
-    }
-
-    @Override
-    public int size() {
-        cache.cleanUp();
-        return (int) cache.estimatedSize();
-    }
-
-    @Override
-    public Set<String> keys() {
-        return Set.copyOf(cache.asMap().keySet());
-    }
-
-    @Override
-    public void clear() {
-        cache.invalidateAll();
-    }
-
-    @Override
-    public void start() {
-        if (cache != null) {
-            return;
-        }
-        cache = Caffeine.newBuilder()
-                .maximumSize(maximumSize)
-                .expireAfter(new Expiry<String, TimedValue>() {
-                    @Override
-                    public long expireAfterCreate(String key, TimedValue value, long currentTime) {
-                        return value.ttlMillis() > 0
-                                ? Duration.ofMillis(value.ttlMillis()).toNanos()
-                                : Long.MAX_VALUE;
-                    }
-
-                    @Override
-                    public long expireAfterUpdate(String key, TimedValue value, long currentTime, long currentDuration) {
-                        return value.ttlMillis() > 0
-                                ? Duration.ofMillis(value.ttlMillis()).toNanos()
-                                : Long.MAX_VALUE;
-                    }
-
-                    @Override
-                    public long expireAfterRead(String key, TimedValue value, long currentTime, long currentDuration) {
-                        return currentDuration;
-                    }
-                })
-                .build();
-    }
-
-    @Override
-    public void stop() {
-        if (cache != null) {
-            cache.invalidateAll();
-            cache.cleanUp();
-            cache = null;
-        }
-    }
-
-    public int getMaximumSize() {
-        return maximumSize;
-    }
-
-    public void setMaximumSize(int maximumSize) {
-        this.maximumSize = maximumSize;
-    }
-
-    private record TimedValue(Object value, long ttlMillis) {
-    }
-}
diff --git a/components/camel-state-store/camel-state-store-caffeine/src/test/java/org/apache/camel/component/statestore/caffeine/CaffeineStateStoreBackendTest.java b/components/camel-state-store/camel-state-store-caffeine/src/test/java/org/apache/camel/component/statestore/caffeine/CaffeineStateStoreBackendTest.java
deleted file mode 100644
index 1fed0911079e..000000000000
--- a/components/camel-state-store/camel-state-store-caffeine/src/test/java/org/apache/camel/component/statestore/caffeine/CaffeineStateStoreBackendTest.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.camel.component.statestore.caffeine;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.camel.BindToRegistry;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.statestore.StateStoreConstants;
-import org.apache.camel.component.statestore.StateStoreOperations;
-import org.apache.camel.test.junit5.CamelTestSupport;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.awaitility.Awaitility.await;
-
-class CaffeineStateStoreBackendTest extends CamelTestSupport {
-
-    @BindToRegistry("caffeineBackend")
-    private final CaffeineStateStoreBackend backend = new CaffeineStateStoreBackend();
-
-    @Test
-    void testPutAndGet() {
-        template.requestBodyAndHeaders(
-                "direct:put", "hello",
-                Map.of(StateStoreConstants.KEY, "key1"));
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(result).isEqualTo("hello");
-    }
-
-    @Test
-    void testPutReturnsOldValue() {
-        template.requestBodyAndHeaders(
-                "direct:put", "first",
-                Map.of(StateStoreConstants.KEY, "key1"));
-
-        Object previous = template.requestBodyAndHeaders(
-                "direct:put", "second",
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(previous).isEqualTo("first");
-    }
-
-    @Test
-    void testDelete() {
-        template.requestBodyAndHeaders(
-                "direct:put", "value",
-                Map.of(StateStoreConstants.KEY, "key1"));
-
-        Object removed = template.requestBodyAndHeaders(
-                "direct:delete", null,
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(removed).isEqualTo("value");
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(result).isNull();
-    }
-
-    @Test
-    void testContains() {
-        template.requestBodyAndHeaders(
-                "direct:put", "value",
-                Map.of(StateStoreConstants.KEY, "key1"));
-
-        Object exists = template.requestBodyAndHeaders(
-                "direct:dynamic", null,
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.contains,
-                        StateStoreConstants.KEY, "key1"));
-        assertThat(exists).isEqualTo(true);
-    }
-
-    @Test
-    @SuppressWarnings("unchecked")
-    void testKeysAndSize() {
-        template.requestBodyAndHeaders(
-                "direct:put", "v1",
-                Map.of(StateStoreConstants.KEY, "a"));
-        template.requestBodyAndHeaders(
-                "direct:put", "v2",
-                Map.of(StateStoreConstants.KEY, "b"));
-
-        Set<String> keys = (Set<String>) template.requestBodyAndHeaders(
-                "direct:dynamic", null,
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.keys));
-        assertThat(keys).containsExactlyInAnyOrder("a", "b");
-
-        Object size = template.requestBodyAndHeaders(
-                "direct:dynamic", null,
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.size));
-        assertThat(size).isEqualTo(2);
-    }
-
-    @Test
-    void testPutIfAbsent() {
-        Object result = template.requestBodyAndHeaders(
-                "direct:dynamic", "first",
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.putIfAbsent,
-                        StateStoreConstants.KEY, "key1"));
-        assertThat(result).isNull();
-
-        result = template.requestBodyAndHeaders(
-                "direct:dynamic", "second",
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.putIfAbsent,
-                        StateStoreConstants.KEY, "key1"));
-        assertThat(result).isEqualTo("first");
-    }
-
-    @Test
-    void testClear() {
-        template.requestBodyAndHeaders(
-                "direct:put", "v1",
-                Map.of(StateStoreConstants.KEY, "a"));
-
-        template.requestBodyAndHeaders(
-                "direct:dynamic", null,
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.clear));
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "a"));
-        assertThat(result).isNull();
-    }
-
-    @Test
-    void testTtlExpiry() {
-        template.requestBodyAndHeaders(
-                "direct:put-ttl", "expiring",
-                Map.of(StateStoreConstants.KEY, "ttlKey"));
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "ttlKey"));
-        assertThat(result).isEqualTo("expiring");
-
-        await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
-            backend.keys(); // trigger Caffeine cleanup
-            Object expired = template.requestBodyAndHeaders(
-                    "direct:get", null,
-                    Map.of(StateStoreConstants.KEY, "ttlKey"));
-            assertThat(expired).isNull();
-        });
-    }
-
-    @Test
-    void testPerMessageTtlHeader() {
-        template.requestBodyAndHeaders(
-                "direct:put", "expiring",
-                Map.of(StateStoreConstants.KEY, "ttlKey",
-                        StateStoreConstants.TTL, 200L));
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "ttlKey"));
-        assertThat(result).isEqualTo("expiring");
-
-        await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
-            backend.keys();
-            Object expired = template.requestBodyAndHeaders(
-                    "direct:get", null,
-                    Map.of(StateStoreConstants.KEY, "ttlKey"));
-            assertThat(expired).isNull();
-        });
-    }
-
-    @Override
-    protected RouteBuilder createRouteBuilder() {
-        return new RouteBuilder() {
-            @Override
-            public void configure() {
-                from("direct:put").to("state-store:myStore?operation=put&backend=#caffeineBackend");
-                from("direct:put-ttl").to("state-store:myStore?operation=put&backend=#caffeineBackend&ttl=200");
-                from("direct:get").to("state-store:myStore?operation=get&backend=#caffeineBackend");
-                from("direct:delete").to("state-store:myStore?operation=delete&backend=#caffeineBackend");
-                from("direct:dynamic").to("state-store:myStore?backend=#caffeineBackend");
-            }
-        };
-    }
-}
diff --git a/components/camel-state-store/camel-state-store-caffeine/src/test/java/org/apache/camel/component/statestore/caffeine/CaffeineStateStorePropertiesTest.java b/components/camel-state-store/camel-state-store-caffeine/src/test/java/org/apache/camel/component/statestore/caffeine/CaffeineStateStorePropertiesTest.java
deleted file mode 100644
index 18d760363ecb..000000000000
--- a/components/camel-state-store/camel-state-store-caffeine/src/test/java/org/apache/camel/component/statestore/caffeine/CaffeineStateStorePropertiesTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.camel.component.statestore.caffeine;
-
-import java.util.Map;
-import java.util.Properties;
-
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.statestore.StateStoreBackend;
-import org.apache.camel.component.statestore.StateStoreConstants;
-import org.apache.camel.test.main.junit5.CamelMainTestSupport;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Tests that a Caffeine backend can be fully configured via properties (camel.beans.*) and auto-discovered without
- * explicit backend=# reference on the endpoint.
- */
-class CaffeineStateStorePropertiesTest extends CamelMainTestSupport {
-
-    @Override
-    protected Properties useOverridePropertiesWithPropertiesComponent() {
-        Properties props = new Properties();
-        props.setProperty("camel.beans.caffeineBackend",
-                "#class:" + CaffeineStateStoreBackend.class.getName());
-        props.setProperty("camel.beans.caffeineBackend.maximumSize", "5000");
-        return props;
-    }
-
-    @Test
-    void testBackendConfiguredViaProperties() {
-        // Verify the bean was created and configured
-        StateStoreBackend backend = context.getRegistry().lookupByNameAndType("caffeineBackend", StateStoreBackend.class);
-        assertThat(backend).isNotNull().isInstanceOf(CaffeineStateStoreBackend.class);
-        assertThat(((CaffeineStateStoreBackend) backend).getMaximumSize()).isEqualTo(5000);
-    }
-
-    @Test
-    void testAutoDiscoveryWithPropertiesConfiguredBackend() {
-        // No backend=#caffeineBackend in the URI — auto-discovery should find it
-        Object previous = template.requestBodyAndHeaders(
-                "direct:put", "hello",
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(previous).isNull();
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(result).isEqualTo("hello");
-    }
-
-    @Test
-    void testExplicitBeanReferenceWithPropertiesConfiguredBackend() {
-        // Explicit backend=#caffeineBackend — should also work
-        Object previous = template.requestBodyAndHeaders(
-                "direct:put-explicit", "world",
-                Map.of(StateStoreConstants.KEY, "key2"));
-        assertThat(previous).isNull();
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get-explicit", null,
-                Map.of(StateStoreConstants.KEY, "key2"));
-        assertThat(result).isEqualTo("world");
-    }
-
-    @Override
-    protected RouteBuilder createRouteBuilder() {
-        return new RouteBuilder() {
-            @Override
-            public void configure() {
-                // Auto-discovery (no backend reference)
-                from("direct:put").to("state-store:myStore?operation=put");
-                from("direct:get").to("state-store:myStore?operation=get");
-                // Explicit bean reference
-                from("direct:put-explicit").to("state-store:explicitStore?operation=put&backend=#caffeineBackend");
-                from("direct:get-explicit").to("state-store:explicitStore?operation=get&backend=#caffeineBackend");
-            }
-        };
-    }
-}
diff --git a/components/camel-state-store/camel-state-store-infinispan/pom.xml b/components/camel-state-store/camel-state-store-infinispan/pom.xml
deleted file mode 100644
index 724c59b84461..000000000000
--- a/components/camel-state-store/camel-state-store-infinispan/pom.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You 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.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.apache.camel</groupId>
-        <artifactId>camel-state-store-parent</artifactId>
-        <version>4.23.0-SNAPSHOT</version>
-    </parent>
-
-    <artifactId>camel-state-store-infinispan</artifactId>
-    <packaging>jar</packaging>
-
-    <name>Camel :: State Store :: Infinispan</name>
-    <description>Camel State Store backend using Infinispan remote (Hot Rod)</description>
-
-    <properties>
-        <firstVersion>4.23.0</firstVersion>
-    </properties>
-
-    <dependencies>
-
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-state-store</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.infinispan</groupId>
-            <artifactId>infinispan-client-hotrod</artifactId>
-            <version>${infinispan-version}</version>
-        </dependency>
-
-        <!-- testing -->
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-test-main-junit5</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.assertj</groupId>
-            <artifactId>assertj-core</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-test-infra-infinispan</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-
-    </dependencies>
-</project>
diff --git a/components/camel-state-store/camel-state-store-infinispan/src/generated/resources/META-INF/services/org/apache/camel/other.properties b/components/camel-state-store/camel-state-store-infinispan/src/generated/resources/META-INF/services/org/apache/camel/other.properties
deleted file mode 100644
index f178128a44a5..000000000000
--- a/components/camel-state-store/camel-state-store-infinispan/src/generated/resources/META-INF/services/org/apache/camel/other.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-# Generated by camel build tools - do NOT edit this file!
-name=state-store-infinispan
-groupId=org.apache.camel
-artifactId=camel-state-store-infinispan
-version=4.23.0-SNAPSHOT
-projectName=Camel :: State Store :: Infinispan
-projectDescription=Camel State Store backend using Infinispan remote (Hot Rod)
diff --git a/components/camel-state-store/camel-state-store-infinispan/src/generated/resources/state-store-infinispan.json b/components/camel-state-store/camel-state-store-infinispan/src/generated/resources/state-store-infinispan.json
deleted file mode 100644
index a047688f0bcf..000000000000
--- a/components/camel-state-store/camel-state-store-infinispan/src/generated/resources/state-store-infinispan.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "other": {
-    "kind": "other",
-    "name": "state-store-infinispan",
-    "title": "State Store Infinispan",
-    "description": "Camel State Store backend using Infinispan remote (Hot Rod)",
-    "deprecated": false,
-    "firstVersion": "4.23.0",
-    "supportLevel": "Preview",
-    "groupId": "org.apache.camel",
-    "artifactId": "camel-state-store-infinispan",
-    "version": "4.23.0-SNAPSHOT"
-  }
-}
diff --git a/components/camel-state-store/camel-state-store-infinispan/src/main/java/org/apache/camel/component/statestore/infinispan/InfinispanStateStoreBackend.java b/components/camel-state-store/camel-state-store-infinispan/src/main/java/org/apache/camel/component/statestore/infinispan/InfinispanStateStoreBackend.java
deleted file mode 100644
index 150315a4b64f..000000000000
--- a/components/camel-state-store/camel-state-store-infinispan/src/main/java/org/apache/camel/component/statestore/infinispan/InfinispanStateStoreBackend.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.camel.component.statestore.infinispan;
-
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.camel.component.statestore.StateStoreBackend;
-import org.infinispan.client.hotrod.RemoteCache;
-import org.infinispan.client.hotrod.RemoteCacheManager;
-import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
-
-/**
- * A {@link StateStoreBackend} implementation backed by Infinispan remote (Hot Rod). Supports per-entry TTL via
- * Infinispan's lifespan parameter.
- *
- * @since 4.23
- */
-public class InfinispanStateStoreBackend implements StateStoreBackend {
-
-    private RemoteCacheManager cacheManager;
-    private RemoteCache<String, Object> cache;
-    private String hosts = "localhost:11222";
-    private String cacheName = "camel-state-store";
-    private boolean managedCacheManager;
-
-    @Override
-    public Object put(String key, Object value, long ttlMillis) {
-        if (ttlMillis > 0) {
-            return cache.put(key, value, ttlMillis, TimeUnit.MILLISECONDS);
-        }
-        return cache.put(key, value);
-    }
-
-    @Override
-    public Object putIfAbsent(String key, Object value, long ttlMillis) {
-        if (ttlMillis > 0) {
-            return cache.putIfAbsent(key, value, ttlMillis, TimeUnit.MILLISECONDS);
-        }
-        return cache.putIfAbsent(key, value);
-    }
-
-    @Override
-    public Object get(String key) {
-        return cache.get(key);
-    }
-
-    @Override
-    public Object delete(String key) {
-        return cache.remove(key);
-    }
-
-    @Override
-    public boolean contains(String key) {
-        return cache.containsKey(key);
-    }
-
-    @Override
-    public Set<String> keys() {
-        return Set.copyOf(cache.keySet());
-    }
-
-    @Override
-    public int size() {
-        return cache.size();
-    }
-
-    @Override
-    public void clear() {
-        cache.clear();
-    }
-
-    @Override
-    public void start() {
-        if (cache != null) {
-            return;
-        }
-        if (cacheManager == null) {
-            ConfigurationBuilder builder = new ConfigurationBuilder();
-            builder.addServers(hosts);
-            builder.forceReturnValues(true);
-            cacheManager = new RemoteCacheManager(builder.build(), true);
-            managedCacheManager = true;
-        }
-        cache = cacheManager.administration().getOrCreateCache(cacheName, (String) null);
-    }
-
-    @Override
-    public void stop() {
-        cache = null;
-        if (managedCacheManager && cacheManager != null) {
-            cacheManager.stop();
-            cacheManager = null;
-            managedCacheManager = false;
-        }
-    }
-
-    public RemoteCacheManager getCacheManager() {
-        return cacheManager;
-    }
-
-    public void setCacheManager(RemoteCacheManager cacheManager) {
-        this.cacheManager = cacheManager;
-    }
-
-    public String getHosts() {
-        return hosts;
-    }
-
-    public void setHosts(String hosts) {
-        this.hosts = hosts;
-    }
-
-    public String getCacheName() {
-        return cacheName;
-    }
-
-    public void setCacheName(String cacheName) {
-        this.cacheName = cacheName;
-    }
-}
diff --git a/components/camel-state-store/camel-state-store-infinispan/src/test/java/org/apache/camel/component/statestore/infinispan/InfinispanStateStoreBackendIT.java b/components/camel-state-store/camel-state-store-infinispan/src/test/java/org/apache/camel/component/statestore/infinispan/InfinispanStateStoreBackendIT.java
deleted file mode 100644
index c4712721f7f2..000000000000
--- a/components/camel-state-store/camel-state-store-infinispan/src/test/java/org/apache/camel/component/statestore/infinispan/InfinispanStateStoreBackendIT.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.camel.component.statestore.infinispan;
-
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.camel.BindToRegistry;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.statestore.StateStoreConstants;
-import org.apache.camel.component.statestore.StateStoreOperations;
-import org.apache.camel.test.infra.infinispan.services.InfinispanService;
-import org.apache.camel.test.infra.infinispan.services.InfinispanServiceFactory;
-import org.apache.camel.test.junit5.CamelTestSupport;
-import org.infinispan.client.hotrod.RemoteCacheManager;
-import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.awaitility.Awaitility.await;
-
-class InfinispanStateStoreBackendIT extends CamelTestSupport {
-
-    private static final boolean IS_MAC_OS = System.getProperty("os.name", "").startsWith("Mac");
-
-    @RegisterExtension
-    static InfinispanService service = InfinispanServiceFactory.createSingletonInfinispanService();
-
-    private InfinispanStateStoreBackend backend;
-    private RemoteCacheManager testCacheManager;
-
-    @AfterEach
-    void cleanUp() {
-        if (testCacheManager != null) {
-            testCacheManager.stop();
-            testCacheManager = null;
-        }
-    }
-
-    @BeforeEach
-    void clearCache() {
-        if (backend != null) {
-            template.requestBodyAndHeaders("direct:op", (Object) null,
-                    Map.of(StateStoreConstants.OPERATION, StateStoreOperations.clear));
-        }
-    }
-
-    @BindToRegistry("infinispanBackend")
-    public InfinispanStateStoreBackend createBackend() {
-        backend = new InfinispanStateStoreBackend();
-
-        ConfigurationBuilder builder = new ConfigurationBuilder();
-        builder.forceReturnValues(true);
-        builder.addServers(service.host() + ":" + service.port());
-        if (service.username() != null) {
-            builder.security().authentication()
-                    .username(service.username())
-                    .password(service.password())
-                    .saslMechanism("SCRAM-SHA-512")
-                    .realm("default")
-                    .serverName("infinispan");
-        }
-        if (IS_MAC_OS) {
-            Properties properties = new Properties();
-            properties.put("infinispan.client.hotrod.client_intelligence", "BASIC");
-            builder.withProperties(properties);
-        }
-        testCacheManager = new RemoteCacheManager(builder.build(), true);
-        backend.setCacheManager(testCacheManager);
-        backend.setCacheName("state-store-test");
-        return backend;
-    }
-
-    @Test
-    void testPutAndGet() {
-        template.requestBodyAndHeaders(
-                "direct:put", "hello",
-                Map.of(StateStoreConstants.KEY, "key1"));
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(result).isEqualTo("hello");
-    }
-
-    @Test
-    void testPutReturnsOldValue() {
-        template.requestBodyAndHeaders(
-                "direct:put", "first",
-                Map.of(StateStoreConstants.KEY, "key1"));
-
-        Object previous = template.requestBodyAndHeaders(
-                "direct:put", "second",
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(previous).isEqualTo("first");
-    }
-
-    @Test
-    void testDelete() {
-        template.requestBodyAndHeaders(
-                "direct:put", "value",
-                Map.of(StateStoreConstants.KEY, "key1"));
-
-        Object removed = template.requestBodyAndHeaders(
-                "direct:delete", null,
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(removed).isEqualTo("value");
-    }
-
-    @Test
-    void testContains() {
-        template.requestBodyAndHeaders(
-                "direct:put", "value",
-                Map.of(StateStoreConstants.KEY, "key1"));
-
-        Object exists = template.requestBodyAndHeaders(
-                "direct:op", null,
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.contains,
-                        StateStoreConstants.KEY, "key1"));
-        assertThat(exists).isEqualTo(true);
-
-        Object notExists = template.requestBodyAndHeaders(
-                "direct:op", null,
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.contains,
-                        StateStoreConstants.KEY, "missing"));
-        assertThat(notExists).isEqualTo(false);
-    }
-
-    @Test
-    void testClear() {
-        template.requestBodyAndHeaders(
-                "direct:put", "v1",
-                Map.of(StateStoreConstants.KEY, "a"));
-
-        template.requestBodyAndHeaders(
-                "direct:op", null,
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.clear));
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "a"));
-        assertThat(result).isNull();
-    }
-
-    @Test
-    void testDeleteNonExistentKey() {
-        Object removed = template.requestBodyAndHeaders(
-                "direct:delete", null,
-                Map.of(StateStoreConstants.KEY, "no-such-key"));
-        assertThat(removed).isNull();
-    }
-
-    @Test
-    @SuppressWarnings("unchecked")
-    void testKeysAndSize() {
-        template.requestBodyAndHeaders(
-                "direct:put", "v1",
-                Map.of(StateStoreConstants.KEY, "a"));
-        template.requestBodyAndHeaders(
-                "direct:put", "v2",
-                Map.of(StateStoreConstants.KEY, "b"));
-
-        Set<String> keys = (Set<String>) template.requestBodyAndHeaders(
-                "direct:op", null,
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.keys));
-        assertThat(keys).containsExactlyInAnyOrder("a", "b");
-
-        Object size = template.requestBodyAndHeaders(
-                "direct:op", null,
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.size));
-        assertThat(size).isEqualTo(2);
-    }
-
-    @Test
-    void testPutIfAbsent() {
-        Object result = template.requestBodyAndHeaders(
-                "direct:op", "first",
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.putIfAbsent,
-                        StateStoreConstants.KEY, "key1"));
-        assertThat(result).isNull();
-
-        result = template.requestBodyAndHeaders(
-                "direct:op", "second",
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.putIfAbsent,
-                        StateStoreConstants.KEY, "key1"));
-        assertThat(result).isEqualTo("first");
-    }
-
-    @Test
-    void testTtlExpiry() {
-        template.requestBodyAndHeaders(
-                "direct:put", "expiring",
-                Map.of(StateStoreConstants.KEY, "ttlKey",
-                        StateStoreConstants.TTL, 500L));
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "ttlKey"));
-        assertThat(result).isEqualTo("expiring");
-
-        await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> {
-            Object expired = template.requestBodyAndHeaders(
-                    "direct:get", null,
-                    Map.of(StateStoreConstants.KEY, "ttlKey"));
-            assertThat(expired).isNull();
-        });
-    }
-
-    @Override
-    protected RouteBuilder createRouteBuilder() {
-        return new RouteBuilder() {
-            @Override
-            public void configure() {
-                from("direct:put").to("state-store:ispnStore?operation=put&backend=#infinispanBackend");
-                from("direct:get").to("state-store:ispnStore?operation=get&backend=#infinispanBackend");
-                from("direct:delete").to("state-store:ispnStore?operation=delete&backend=#infinispanBackend");
-                from("direct:op").to("state-store:ispnStore?backend=#infinispanBackend");
-            }
-        };
-    }
-}
diff --git a/components/camel-state-store/camel-state-store-infinispan/src/test/java/org/apache/camel/component/statestore/infinispan/InfinispanStateStorePropertiesIT.java b/components/camel-state-store/camel-state-store-infinispan/src/test/java/org/apache/camel/component/statestore/infinispan/InfinispanStateStorePropertiesIT.java
deleted file mode 100644
index b10e74feec11..000000000000
--- a/components/camel-state-store/camel-state-store-infinispan/src/test/java/org/apache/camel/component/statestore/infinispan/InfinispanStateStorePropertiesIT.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.camel.component.statestore.infinispan;
-
-import java.util.Map;
-import java.util.Properties;
-
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.statestore.StateStoreBackend;
-import org.apache.camel.component.statestore.StateStoreConstants;
-import org.apache.camel.spi.Registry;
-import org.apache.camel.test.infra.infinispan.services.InfinispanService;
-import org.apache.camel.test.infra.infinispan.services.InfinispanServiceFactory;
-import org.apache.camel.test.main.junit5.CamelMainTestSupport;
-import org.infinispan.client.hotrod.RemoteCacheManager;
-import org.infinispan.client.hotrod.configuration.ConfigurationBuilder;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Tests that an Infinispan backend can be configured via properties (camel.beans.*) and auto-discovered. The backend is
- * created via properties but the {@link RemoteCacheManager} is injected programmatically since it requires
- * authentication and platform-specific configuration that cannot be expressed as simple properties.
- */
-class InfinispanStateStorePropertiesIT extends CamelMainTestSupport {
-
-    private static final boolean IS_MAC_OS = System.getProperty("os.name", "").startsWith("Mac");
-
-    @RegisterExtension
-    static InfinispanService service = InfinispanServiceFactory.createSingletonInfinispanService();
-
-    private RemoteCacheManager testCacheManager;
-
-    @AfterEach
-    void cleanUp() {
-        if (testCacheManager != null) {
-            testCacheManager.stop();
-            testCacheManager = null;
-        }
-    }
-
-    @Override
-    protected Properties useOverridePropertiesWithPropertiesComponent() {
-        Properties props = new Properties();
-        props.setProperty("camel.beans.infinispanBackend",
-                "#class:" + InfinispanStateStoreBackend.class.getName());
-        props.setProperty("camel.beans.infinispanBackend.cacheName", "state-store-props-test");
-        return props;
-    }
-
-    @Override
-    protected void bindToRegistry(Registry registry) throws Exception {
-        super.bindToRegistry(registry);
-        // Inject a pre-configured RemoteCacheManager into the property-created backend.
-        // Authentication and platform-specific settings require programmatic configuration.
-        InfinispanStateStoreBackend backend
-                = registry.lookupByNameAndType("infinispanBackend", InfinispanStateStoreBackend.class);
-        if (backend != null) {
-            backend.setCacheManager(createCacheManager());
-        }
-    }
-
-    private RemoteCacheManager createCacheManager() {
-        ConfigurationBuilder builder = new ConfigurationBuilder();
-        builder.forceReturnValues(true);
-        builder.addServers(service.host() + ":" + service.port());
-        if (service.username() != null) {
-            builder.security().authentication()
-                    .username(service.username())
-                    .password(service.password())
-                    .saslMechanism("SCRAM-SHA-512")
-                    .realm("default")
-                    .serverName("infinispan");
-        }
-        if (IS_MAC_OS) {
-            Properties properties = new Properties();
-            properties.put("infinispan.client.hotrod.client_intelligence", "BASIC");
-            builder.withProperties(properties);
-        }
-        testCacheManager = new RemoteCacheManager(builder.build(), true);
-        return testCacheManager;
-    }
-
-    @Test
-    void testBackendConfiguredViaProperties() {
-        StateStoreBackend backend = context.getRegistry().lookupByNameAndType("infinispanBackend", StateStoreBackend.class);
-        assertThat(backend).isNotNull().isInstanceOf(InfinispanStateStoreBackend.class);
-        assertThat(((InfinispanStateStoreBackend) backend).getCacheName()).isEqualTo("state-store-props-test");
-    }
-
-    @Test
-    void testAutoDiscoveryPutAndGet() {
-        // No backend=#infinispanBackend in the URI — auto-discovery should find it
-        Object previous = template.requestBodyAndHeaders(
-                "direct:put", "hello",
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(previous).isNull();
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(result).isEqualTo("hello");
-    }
-
-    @Override
-    protected RouteBuilder createRouteBuilder() {
-        return new RouteBuilder() {
-            @Override
-            public void configure() {
-                // No backend=# reference — relies on auto-discovery
-                from("direct:put").to("state-store:ispnStore?operation=put");
-                from("direct:get").to("state-store:ispnStore?operation=get");
-            }
-        };
-    }
-}
diff --git a/components/camel-state-store/camel-state-store-redis/pom.xml b/components/camel-state-store/camel-state-store-redis/pom.xml
deleted file mode 100644
index bac53dba3784..000000000000
--- a/components/camel-state-store/camel-state-store-redis/pom.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You 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.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.apache.camel</groupId>
-        <artifactId>camel-state-store-parent</artifactId>
-        <version>4.23.0-SNAPSHOT</version>
-    </parent>
-
-    <artifactId>camel-state-store-redis</artifactId>
-    <packaging>jar</packaging>
-
-    <name>Camel :: State Store :: Redis</name>
-    <description>Camel State Store backend using Redisson (Redis)</description>
-
-    <properties>
-        <firstVersion>4.23.0</firstVersion>
-    </properties>
-
-    <dependencies>
-
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-state-store</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.redisson</groupId>
-            <artifactId>redisson</artifactId>
-            <version>${redisson-version}</version>
-        </dependency>
-
-        <!-- testing -->
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-test-main-junit5</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.assertj</groupId>
-            <artifactId>assertj-core</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.camel</groupId>
-            <artifactId>camel-test-infra-redis</artifactId>
-            <version>${project.version}</version>
-            <scope>test</scope>
-        </dependency>
-
-    </dependencies>
-</project>
diff --git a/components/camel-state-store/camel-state-store-redis/src/generated/resources/META-INF/services/org/apache/camel/other.properties b/components/camel-state-store/camel-state-store-redis/src/generated/resources/META-INF/services/org/apache/camel/other.properties
deleted file mode 100644
index bd0bb6ee55ee..000000000000
--- a/components/camel-state-store/camel-state-store-redis/src/generated/resources/META-INF/services/org/apache/camel/other.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-# Generated by camel build tools - do NOT edit this file!
-name=state-store-redis
-groupId=org.apache.camel
-artifactId=camel-state-store-redis
-version=4.23.0-SNAPSHOT
-projectName=Camel :: State Store :: Redis
-projectDescription=Camel State Store backend using Redisson (Redis)
diff --git a/components/camel-state-store/camel-state-store-redis/src/generated/resources/state-store-redis.json b/components/camel-state-store/camel-state-store-redis/src/generated/resources/state-store-redis.json
deleted file mode 100644
index 20889cda5326..000000000000
--- a/components/camel-state-store/camel-state-store-redis/src/generated/resources/state-store-redis.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "other": {
-    "kind": "other",
-    "name": "state-store-redis",
-    "title": "State Store Redis",
-    "description": "Camel State Store backend using Redisson (Redis)",
-    "deprecated": false,
-    "firstVersion": "4.23.0",
-    "supportLevel": "Preview",
-    "groupId": "org.apache.camel",
-    "artifactId": "camel-state-store-redis",
-    "version": "4.23.0-SNAPSHOT"
-  }
-}
diff --git a/components/camel-state-store/camel-state-store-redis/src/main/java/org/apache/camel/component/statestore/redis/RedisStateStoreBackend.java b/components/camel-state-store/camel-state-store-redis/src/main/java/org/apache/camel/component/statestore/redis/RedisStateStoreBackend.java
deleted file mode 100644
index 861e08db92ab..000000000000
--- a/components/camel-state-store/camel-state-store-redis/src/main/java/org/apache/camel/component/statestore/redis/RedisStateStoreBackend.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.camel.component.statestore.redis;
-
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.camel.component.statestore.StateStoreBackend;
-import org.redisson.Redisson;
-import org.redisson.api.RMapCache;
-import org.redisson.api.RedissonClient;
-import org.redisson.config.Config;
-
-/**
- * A {@link StateStoreBackend} implementation backed by Redis using Redisson. Uses {@link RMapCache} for per-entry TTL
- * support.
- *
- * @since 4.23
- */
-public class RedisStateStoreBackend implements StateStoreBackend {
-
-    private RedissonClient redisson;
-    private RMapCache<String, Object> mapCache;
-    private String redisUrl = "redis://localhost:6379";
-    private String mapName = "camel-state-store";
-    private boolean managedRedisson;
-
-    @Override
-    public Object put(String key, Object value, long ttlMillis) {
-        if (ttlMillis > 0) {
-            return mapCache.put(key, value, ttlMillis, TimeUnit.MILLISECONDS);
-        }
-        return mapCache.put(key, value);
-    }
-
-    @Override
-    public Object putIfAbsent(String key, Object value, long ttlMillis) {
-        if (ttlMillis > 0) {
-            return mapCache.putIfAbsent(key, value, ttlMillis, TimeUnit.MILLISECONDS);
-        }
-        return mapCache.putIfAbsent(key, value);
-    }
-
-    @Override
-    public Object get(String key) {
-        return mapCache.get(key);
-    }
-
-    @Override
-    public Object delete(String key) {
-        return mapCache.remove(key);
-    }
-
-    @Override
-    public boolean contains(String key) {
-        return mapCache.containsKey(key);
-    }
-
-    @Override
-    public Set<String> keys() {
-        return Set.copyOf(mapCache.keySet());
-    }
-
-    @Override
-    public int size() {
-        return mapCache.size();
-    }
-
-    @Override
-    public void clear() {
-        mapCache.clear();
-    }
-
-    @Override
-    public void start() {
-        if (redisson == null) {
-            Config config = new Config();
-            config.useSingleServer().setAddress(redisUrl);
-            redisson = Redisson.create(config);
-            managedRedisson = true;
-        }
-        mapCache = redisson.getMapCache(mapName);
-    }
-
-    @Override
-    public void stop() {
-        mapCache = null;
-        if (managedRedisson && redisson != null) {
-            redisson.shutdown();
-            redisson = null;
-            managedRedisson = false;
-        }
-    }
-
-    public RedissonClient getRedisson() {
-        return redisson;
-    }
-
-    public void setRedisson(RedissonClient redisson) {
-        this.redisson = redisson;
-    }
-
-    public String getRedisUrl() {
-        return redisUrl;
-    }
-
-    public void setRedisUrl(String redisUrl) {
-        this.redisUrl = redisUrl;
-    }
-
-    public String getMapName() {
-        return mapName;
-    }
-
-    public void setMapName(String mapName) {
-        this.mapName = mapName;
-    }
-}
diff --git a/components/camel-state-store/camel-state-store-redis/src/test/java/org/apache/camel/component/statestore/redis/RedisStateStoreBackendIT.java b/components/camel-state-store/camel-state-store-redis/src/test/java/org/apache/camel/component/statestore/redis/RedisStateStoreBackendIT.java
deleted file mode 100644
index 98200385ccfe..000000000000
--- a/components/camel-state-store/camel-state-store-redis/src/test/java/org/apache/camel/component/statestore/redis/RedisStateStoreBackendIT.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.camel.component.statestore.redis;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.camel.BindToRegistry;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.statestore.StateStoreConstants;
-import org.apache.camel.component.statestore.StateStoreOperations;
-import org.apache.camel.test.infra.redis.services.RedisService;
-import org.apache.camel.test.infra.redis.services.RedisServiceFactory;
-import org.apache.camel.test.junit5.CamelTestSupport;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.awaitility.Awaitility.await;
-
-class RedisStateStoreBackendIT extends CamelTestSupport {
-
-    @RegisterExtension
-    static RedisService service = RedisServiceFactory.createService();
-
-    private RedisStateStoreBackend backend;
-
-    @BindToRegistry("redisBackend")
-    public RedisStateStoreBackend createBackend() {
-        backend = new RedisStateStoreBackend();
-        backend.setRedisUrl("redis://" + service.getServiceAddress());
-        backend.setMapName("test-state-store-" + System.nanoTime());
-        return backend;
-    }
-
-    @Test
-    void testPutAndGet() {
-        template.requestBodyAndHeaders(
-                "direct:put", "hello",
-                Map.of(StateStoreConstants.KEY, "key1"));
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(result).isEqualTo("hello");
-    }
-
-    @Test
-    void testPutReturnsOldValue() {
-        template.requestBodyAndHeaders(
-                "direct:put", "first",
-                Map.of(StateStoreConstants.KEY, "key1"));
-
-        Object previous = template.requestBodyAndHeaders(
-                "direct:put", "second",
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(previous).isEqualTo("first");
-    }
-
-    @Test
-    void testDelete() {
-        template.requestBodyAndHeaders(
-                "direct:put", "value",
-                Map.of(StateStoreConstants.KEY, "key1"));
-
-        Object removed = template.requestBodyAndHeaders(
-                "direct:delete", null,
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(removed).isEqualTo("value");
-
-        // verify key is gone
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(result).isNull();
-    }
-
-    @Test
-    void testDeleteNonExistentKey() {
-        Object removed = template.requestBodyAndHeaders(
-                "direct:delete", null,
-                Map.of(StateStoreConstants.KEY, "no-such-key"));
-        assertThat(removed).isNull();
-    }
-
-    @Test
-    void testContains() {
-        template.requestBodyAndHeaders(
-                "direct:put", "value",
-                Map.of(StateStoreConstants.KEY, "key1"));
-
-        Object exists = template.requestBodyAndHeaders(
-                "direct:op", null,
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.contains,
-                        StateStoreConstants.KEY, "key1"));
-        assertThat(exists).isEqualTo(true);
-
-        Object notExists = template.requestBodyAndHeaders(
-                "direct:op", null,
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.contains,
-                        StateStoreConstants.KEY, "missing"));
-        assertThat(notExists).isEqualTo(false);
-    }
-
-    @Test
-    @SuppressWarnings("unchecked")
-    void testKeysAndSize() {
-        template.requestBodyAndHeaders(
-                "direct:put", "v1",
-                Map.of(StateStoreConstants.KEY, "a"));
-        template.requestBodyAndHeaders(
-                "direct:put", "v2",
-                Map.of(StateStoreConstants.KEY, "b"));
-
-        Set<String> keys = (Set<String>) template.requestBodyAndHeaders(
-                "direct:op", null,
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.keys));
-        assertThat(keys).containsExactlyInAnyOrder("a", "b");
-
-        Object size = template.requestBodyAndHeaders(
-                "direct:op", null,
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.size));
-        assertThat(size).isEqualTo(2);
-    }
-
-    @Test
-    void testPutIfAbsent() {
-        Object result = template.requestBodyAndHeaders(
-                "direct:op", "first",
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.putIfAbsent,
-                        StateStoreConstants.KEY, "key1"));
-        assertThat(result).isNull();
-
-        result = template.requestBodyAndHeaders(
-                "direct:op", "second",
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.putIfAbsent,
-                        StateStoreConstants.KEY, "key1"));
-        assertThat(result).isEqualTo("first");
-    }
-
-    @Test
-    void testClear() {
-        template.requestBodyAndHeaders(
-                "direct:put", "v1",
-                Map.of(StateStoreConstants.KEY, "a"));
-
-        template.requestBodyAndHeaders(
-                "direct:op", null,
-                Map.of(StateStoreConstants.OPERATION, StateStoreOperations.clear));
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "a"));
-        assertThat(result).isNull();
-    }
-
-    @Test
-    void testTtlExpiry() {
-        template.requestBodyAndHeaders(
-                "direct:put", "expiring",
-                Map.of(StateStoreConstants.KEY, "ttlKey",
-                        StateStoreConstants.TTL, 500L));
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "ttlKey"));
-        assertThat(result).isEqualTo("expiring");
-
-        await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> {
-            Object expired = template.requestBodyAndHeaders(
-                    "direct:get", null,
-                    Map.of(StateStoreConstants.KEY, "ttlKey"));
-            assertThat(expired).isNull();
-        });
-    }
-
-    @Override
-    protected RouteBuilder createRouteBuilder() {
-        return new RouteBuilder() {
-            @Override
-            public void configure() {
-                from("direct:put").to("state-store:redisStore?operation=put&backend=#redisBackend");
-                from("direct:get").to("state-store:redisStore?operation=get&backend=#redisBackend");
-                from("direct:delete").to("state-store:redisStore?operation=delete&backend=#redisBackend");
-                from("direct:op").to("state-store:redisStore?backend=#redisBackend");
-            }
-        };
-    }
-}
diff --git a/components/camel-state-store/camel-state-store-redis/src/test/java/org/apache/camel/component/statestore/redis/RedisStateStorePropertiesIT.java b/components/camel-state-store/camel-state-store-redis/src/test/java/org/apache/camel/component/statestore/redis/RedisStateStorePropertiesIT.java
deleted file mode 100644
index 07b849e47938..000000000000
--- a/components/camel-state-store/camel-state-store-redis/src/test/java/org/apache/camel/component/statestore/redis/RedisStateStorePropertiesIT.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.camel.component.statestore.redis;
-
-import java.util.Map;
-import java.util.Properties;
-
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.statestore.StateStoreBackend;
-import org.apache.camel.component.statestore.StateStoreConstants;
-import org.apache.camel.test.infra.redis.services.RedisService;
-import org.apache.camel.test.infra.redis.services.RedisServiceFactory;
-import org.apache.camel.test.main.junit5.CamelMainTestSupport;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Tests that a Redis backend can be fully configured via properties (camel.beans.*) and auto-discovered without
- * explicit backend=# reference on the endpoint.
- */
-class RedisStateStorePropertiesIT extends CamelMainTestSupport {
-
-    @RegisterExtension
-    static RedisService service = RedisServiceFactory.createService();
-
-    @Override
-    protected Properties useOverridePropertiesWithPropertiesComponent() {
-        Properties props = new Properties();
-        props.setProperty("camel.beans.redisBackend",
-                "#class:" + RedisStateStoreBackend.class.getName());
-        props.setProperty("camel.beans.redisBackend.redisUrl", "redis://" + service.getServiceAddress());
-        props.setProperty("camel.beans.redisBackend.mapName", "test-props-" + System.nanoTime());
-        return props;
-    }
-
-    @Test
-    void testBackendConfiguredViaProperties() {
-        StateStoreBackend backend = context.getRegistry().lookupByNameAndType("redisBackend", StateStoreBackend.class);
-        assertThat(backend).isNotNull().isInstanceOf(RedisStateStoreBackend.class);
-    }
-
-    @Test
-    void testAutoDiscoveryPutAndGet() {
-        // No backend=#redisBackend in the URI — auto-discovery should find it
-        Object previous = template.requestBodyAndHeaders(
-                "direct:put", "hello",
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(previous).isNull();
-
-        Object result = template.requestBodyAndHeaders(
-                "direct:get", null,
-                Map.of(StateStoreConstants.KEY, "key1"));
-        assertThat(result).isEqualTo("hello");
-    }
-
-    @Override
-    protected RouteBuilder createRouteBuilder() {
-        return new RouteBuilder() {
-            @Override
-            public void configure() {
-                // No backend=# reference — relies on auto-discovery
-                from("direct:put").to("state-store:redisStore?operation=put");
-                from("direct:get").to("state-store:redisStore?operation=get");
-            }
-        };
-    }
-}
diff --git a/components/camel-state-store/camel-state-store/src/generated/java/org/apache/camel/component/statestore/StateStoreEndpointConfigurer.java b/components/camel-state-store/camel-state-store/src/generated/java/org/apache/camel/component/statestore/StateStoreEndpointConfigurer.java
index a9c3c59a868f..30ca4c9d160e 100644
--- a/components/camel-state-store/camel-state-store/src/generated/java/org/apache/camel/component/statestore/StateStoreEndpointConfigurer.java
+++ b/components/camel-state-store/camel-state-store/src/generated/java/org/apache/camel/component/statestore/StateStoreEndpointConfigurer.java
@@ -23,7 +23,7 @@ public class StateStoreEndpointConfigurer extends PropertyConfigurerSupport impl
     public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
         StateStoreEndpoint target = (StateStoreEndpoint) obj;
         switch (ignoreCase ? name.toLowerCase() : name) {
-        case "backend": target.setBackend(property(camelContext, org.apache.camel.component.statestore.StateStoreBackend.class, value)); return true;
+        case "backend": target.setBackend(property(camelContext, org.apache.camel.spi.KeyValueRepository.class, value)); return true;
         case "lazystartproducer":
         case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true;
         case "operation": target.setOperation(property(camelContext, org.apache.camel.component.statestore.StateStoreOperations.class, value)); return true;
@@ -35,7 +35,7 @@ public class StateStoreEndpointConfigurer extends PropertyConfigurerSupport impl
     @Override
     public Class<?> getOptionType(String name, boolean ignoreCase) {
         switch (ignoreCase ? name.toLowerCase() : name) {
-        case "backend": return org.apache.camel.component.statestore.StateStoreBackend.class;
+        case "backend": return org.apache.camel.spi.KeyValueRepository.class;
         case "lazystartproducer":
         case "lazyStartProducer": return boolean.class;
         case "operation": return org.apache.camel.component.statestore.StateStoreOperations.class;
diff --git a/components/camel-state-store/camel-state-store/src/generated/resources/META-INF/org/apache/camel/component/statestore/state-store.json b/components/camel-state-store/camel-state-store/src/generated/resources/META-INF/org/apache/camel/component/statestore/state-store.json
index d90c315d879c..470d0b127426 100644
--- a/components/camel-state-store/camel-state-store/src/generated/resources/META-INF/org/apache/camel/component/statestore/state-store.json
+++ b/components/camel-state-store/camel-state-store/src/generated/resources/META-INF/org/apache/camel/component/statestore/state-store.json
@@ -3,7 +3,7 @@
     "kind": "component",
     "name": "state-store",
     "title": "State Store",
-    "description": "Perform key-value operations against a pluggable state store backend.",
+    "description": "Perform key-value operations against a pluggable KeyValueRepository backend.",
     "deprecated": false,
     "firstVersion": "4.23.0",
     "label": "cache",
@@ -37,6 +37,6 @@
     "operation": { "index": 1, "kind": "parameter", "displayName": "Operation", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "org.apache.camel.component.statestore.StateStoreOperations", "enum": [ "put", "putIfAbsent", "get", "delete", "contains", "keys", "size", "clear" ], "deprecated": false, "autowired": false, "secret": false, "description": "The default operation to perform" },
     "ttl": { "index": 2, "kind": "parameter", "displayName": "Ttl", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 0, "description": "Time-to-live in milliseconds for entries. 0 means no expiry." },
     "lazyStartProducer": { "index": 3, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produc [...]
-    "backend": { "index": 4, "kind": "parameter", "displayName": "Backend", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.statestore.StateStoreBackend", "deprecated": false, "autowired": false, "secret": false, "description": "The backend to use. If not set, auto-discovers a single StateStoreBackend from the registry, or falls back to an in-memory store." }
+    "backend": { "index": 4, "kind": "parameter", "displayName": "Backend", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.KeyValueRepository", "deprecated": false, "autowired": false, "secret": false, "description": "The backend to use. If not set, auto-discovers a single KeyValueRepository from the registry, or falls back to an in-memory store." }
   }
 }
diff --git a/components/camel-state-store/camel-state-store/src/main/docs/state-store-component.adoc b/components/camel-state-store/camel-state-store/src/main/docs/state-store-component.adoc
index c37fb9acaf18..e110ccc0bca5 100644
--- a/components/camel-state-store/camel-state-store/src/main/docs/state-store-component.adoc
+++ b/components/camel-state-store/camel-state-store/src/main/docs/state-store-component.adoc
@@ -2,7 +2,7 @@
 :doctitle: State Store
 :shortname: state-store
 :artifactid: camel-state-store
-:description: Perform key-value operations against a pluggable state store backend.
+:description: Perform key-value operations against a pluggable KeyValueRepository backend.
 :since: 4.23
 :supportlevel: Preview
 :tabs-sync-option:
@@ -12,13 +12,14 @@
 
 *{component-header}*
 
-The State Store component provides a simple, unified key-value store API with pluggable backends.
-It is useful for caching, session state, and scenarios where you need a simple object store
-(similar to MuleSoft's Object Store).
+The State Store component provides a simple, unified key-value store API backed by the
+`KeyValueRepository` SPI from `camel-api`. It is useful for caching, session state, and
+scenarios where you need a simple object store (similar to MuleSoft's Object Store).
 
-By default, an in-memory backend is used (based on `ConcurrentHashMap`), but you can plug in
-any custom backend by implementing the `StateStoreBackend` interface or using one of the
-provided backend modules:
+By default, an in-memory backend is used (`MemoryKeyValueRepository` from `camel-support`),
+but you can plug in any `KeyValueRepository` implementation. The same `KeyValueRepository`
+can also be used as the backend for the Idempotent Consumer and Aggregator EIPs via the
+`KeyValueIdempotentRepository` and `KeyValueAggregationRepository` adapters.
 
 == When to use State Store vs individual components
 
@@ -31,17 +32,9 @@ Use State Store when:
 
 * You need a *simple key-value API* and want to switch backends without changing route logic.
 * You are *migrating from MuleSoft* and want an Object Store equivalent.
-* You want *backend portability* — develop with in-memory, deploy with Redis or Infinispan.
-* Your use case is limited to *put, putIfAbsent, get, delete, contains, keys, size, clear* operations.
-
-[width="100%",cols="1,2,1",options="header"]
-|===
-| Backend | Module | Description
-| In-Memory | `camel-state-store` | Default. Uses `ConcurrentHashMap` with lazy TTL expiry. No external dependencies.
-| Caffeine | `camel-state-store-caffeine` | High-performance local cache with proper eviction and per-entry TTL.
-| Redis | `camel-state-store-redis` | Distributed store via Redisson. Supports per-entry TTL natively.
-| Infinispan | `camel-state-store-infinispan` | Distributed cache via Hot Rod client. Supports per-entry TTL via lifespan.
-|===
+* You want *backend portability* — develop with in-memory, deploy with any `KeyValueRepository`.
+* Your use case is limited to *put, get, delete, contains, keys* operations.
+* You want a *single backend* to serve state store, idempotent consumer, and aggregation patterns.
 
 == URI Format
 
@@ -164,226 +157,35 @@ from("direct:init")
 === Backend auto-discovery
 
 If no `backend` option is specified on the endpoint, the component automatically looks up a
-`StateStoreBackend` bean from the Camel registry. If exactly one is found, it is used for all
-endpoints. If none is found, the default in-memory backend is used.
+`KeyValueRepository` bean from the Camel registry. If exactly one is found, it is used for all
+endpoints. If none is found, the default in-memory backend (`MemoryKeyValueRepository`) is used.
 
 This means you can configure a backend once (via Java or properties) and all `state-store`
 endpoints will use it without needing `backend=#beanName` on each endpoint URI.
 
-=== Configuring backends via properties
-
-Backends can be configured entirely via `application.properties` using Camel's `camel.beans.*`
-syntax, without writing any Java code. This is especially useful for YAML DSL or Camel JBang users.
-
-[tabs]
-====
-Caffeine::
-+
-[source,properties]
-----
-# application.properties
-camel.beans.caffeineBackend = #class:org.apache.camel.component.statestore.caffeine.CaffeineStateStoreBackend
-camel.beans.caffeineBackend.maximumSize = 50000
-----
-
-Redis::
-+
-[source,properties]
-----
-# application.properties
-camel.beans.redisBackend = #class:org.apache.camel.component.statestore.redis.RedisStateStoreBackend
-camel.beans.redisBackend.redisUrl = redis://myhost:6379
-camel.beans.redisBackend.mapName = my-app-state
-----
-
-Infinispan::
-+
-[source,properties]
-----
-# application.properties
-camel.beans.infinispanBackend = #class:org.apache.camel.component.statestore.infinispan.InfinispanStateStoreBackend
-camel.beans.infinispanBackend.hosts = myhost:11222
-camel.beans.infinispanBackend.cacheName = my-cache
-----
-====
-
-With the backend configured via properties and auto-discovery, no `backend=#...` reference
-is needed in the route:
-
-[source,yaml]
-----
-- route:
-    from:
-      uri: direct:store
-    steps:
-      - setHeader:
-          name: CamelStateStoreKey
-          constant: myKey
-      - to:
-          uri: state-store:myStore?operation=put
-----
-
 === In-Memory (default)
 
-The default backend stores entries in a `ConcurrentHashMap`. TTL expiry is lazy -- entries are
-checked and removed on access rather than by a background thread.
+The default backend (`MemoryKeyValueRepository`) stores entries in a `ConcurrentHashMap`. TTL
+expiry is lazy -- entries are checked and removed on access rather than by a background thread.
 
 No additional dependency is needed beyond `camel-state-store`.
 
-=== Caffeine
-
-Add the dependency:
-
-[source,xml]
-----
-<dependency>
-    <groupId>org.apache.camel</groupId>
-    <artifactId>camel-state-store-caffeine</artifactId>
-</dependency>
-----
-
-[tabs]
-====
-Java::
-+
-[source,java]
-----
-@BindToRegistry("caffeineBackend")
-public CaffeineStateStoreBackend caffeine() {
-    CaffeineStateStoreBackend backend = new CaffeineStateStoreBackend();
-    backend.setMaximumSize(50_000); // default is 10,000
-    return backend;
-}
-----
-
-Properties::
-+
-[source,properties]
-----
-camel.beans.caffeineBackend = #class:org.apache.camel.component.statestore.caffeine.CaffeineStateStoreBackend
-camel.beans.caffeineBackend.maximumSize = 50000
-----
-====
-
-With auto-discovery, the backend is picked up automatically. You can also reference it explicitly:
-
-[source,java]
-----
-from("direct:store")
-    .to("state-store:myStore?operation=put&backend=#caffeineBackend");
-----
-
-Caffeine provides proper eviction policies and active TTL expiration using variable expiry.
-
-=== Redis
-
-Add the dependency:
-
-[source,xml]
-----
-<dependency>
-    <groupId>org.apache.camel</groupId>
-    <artifactId>camel-state-store-redis</artifactId>
-</dependency>
-----
-
-[tabs]
-====
-Java::
-+
-[source,java]
-----
-@BindToRegistry("redisBackend")
-public RedisStateStoreBackend redis() {
-    RedisStateStoreBackend backend = new RedisStateStoreBackend();
-    backend.setRedisUrl("redis://myhost:6379");
-    backend.setMapName("my-app-state"); // Redis map name
-    return backend;
-}
-----
-
-Properties::
-+
-[source,properties]
-----
-camel.beans.redisBackend = #class:org.apache.camel.component.statestore.redis.RedisStateStoreBackend
-camel.beans.redisBackend.redisUrl = redis://myhost:6379
-camel.beans.redisBackend.mapName = my-app-state
-----
-====
-
-You can also inject a pre-configured `RedissonClient`:
-
-[source,java]
-----
-backend.setRedisson(existingRedissonClient);
-----
-
-Redis provides native per-entry TTL via `RMapCache`. Data is distributed and persisted according
-to your Redis configuration.
-
-=== Infinispan
-
-Add the dependency:
-
-[source,xml]
-----
-<dependency>
-    <groupId>org.apache.camel</groupId>
-    <artifactId>camel-state-store-infinispan</artifactId>
-</dependency>
-----
-
-[tabs]
-====
-Java::
-+
-[source,java]
-----
-@BindToRegistry("infinispanBackend")
-public InfinispanStateStoreBackend infinispan() {
-    InfinispanStateStoreBackend backend = new InfinispanStateStoreBackend();
-    backend.setHosts("myhost:11222");
-    backend.setCacheName("my-cache");
-    return backend;
-}
-----
-
-Properties::
-+
-[source,properties]
-----
-camel.beans.infinispanBackend = #class:org.apache.camel.component.statestore.infinispan.InfinispanStateStoreBackend
-camel.beans.infinispanBackend.hosts = myhost:11222
-camel.beans.infinispanBackend.cacheName = my-cache
-----
-====
-
-You can also inject a pre-configured `RemoteCacheManager`:
-
-[source,java]
-----
-backend.setCacheManager(existingCacheManager);
-----
-
-Infinispan provides native per-entry TTL via the lifespan parameter and supports distributed caching.
-
 == Custom Backend
 
-Implement the `StateStoreBackend` interface to create your own backend:
+Implement the `KeyValueRepository` interface (from `org.apache.camel.spi`) to create your own backend:
 
 [source,java]
 ----
-public class MyCustomBackend implements StateStoreBackend {
+public class MyCustomBackend extends ServiceSupport implements KeyValueRepository {
 
     @Override
-    public Object put(String key, Object value, long ttlMillis) {
-        // store the value, return previous
+    public Object get(String key) {
+        // retrieve the value
     }
 
     @Override
-    public Object get(String key) {
-        // retrieve the value
+    public Object put(String key, Object value, long ttlMillis) {
+        // store the value; return the previous value or null
     }
 
     @Override
@@ -405,16 +207,6 @@ public class MyCustomBackend implements StateStoreBackend {
     public void clear() {
         // remove all entries
     }
-
-    @Override
-    public void start() {
-        // initialize connections
-    }
-
-    @Override
-    public void stop() {
-        // clean up resources
-    }
 }
 ----
 
@@ -428,3 +220,24 @@ Then reference it via bean or let auto-discovery find it:
 from("direct:store")
     .to("state-store:myStore?operation=put&backend=#myCustomBackend");
 ----
+
+=== Sharing a backend across patterns
+
+Because `KeyValueRepository` is the unified SPI, the same implementation can be reused as the
+backend for the Idempotent Consumer and Aggregator EIPs:
+
+[source,java]
+----
+@BindToRegistry("kvRepo")
+public KeyValueRepository kvRepo() {
+    return new MemoryKeyValueRepository();
+}
+----
+
+With a single `KeyValueRepository` in the registry:
+
+* The State Store component auto-discovers and uses it.
+* The Idempotent Consumer EIP auto-discovers and wraps it in a `KeyValueIdempotentRepository`.
+* The Aggregator EIP auto-discovers and wraps it in a `KeyValueAggregationRepository`.
+
+No explicit wiring is needed — all three patterns share the same backend.
diff --git a/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/InMemoryStateStoreBackend.java b/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/InMemoryStateStoreBackend.java
deleted file mode 100644
index e98511c903a5..000000000000
--- a/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/InMemoryStateStoreBackend.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.camel.component.statestore;
-
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Default in-memory implementation of {@link StateStoreBackend} using a {@link ConcurrentHashMap}. Supports optional
- * TTL with lazy expiry (entries are checked on access, no background thread).
- *
- * @since 4.23
- */
-public class InMemoryStateStoreBackend implements StateStoreBackend {
-
-    private final ConcurrentHashMap<String, Entry> store = new ConcurrentHashMap<>();
-
-    @Override
-    public Object put(String key, Object value, long ttlMillis) {
-        long expiresAt = ttlMillis > 0 ? System.currentTimeMillis() + ttlMillis : 0;
-        Entry previous = store.put(key, new Entry(value, expiresAt));
-        if (previous != null && !previous.isExpired()) {
-            return previous.value();
-        }
-        return null;
-    }
-
-    @Override
-    public Object get(String key) {
-        Entry entry = store.get(key);
-        if (entry == null) {
-            return null;
-        }
-        if (entry.isExpired()) {
-            store.remove(key, entry);
-            return null;
-        }
-        return entry.value();
-    }
-
-    @Override
-    public Object delete(String key) {
-        Entry entry = store.remove(key);
-        if (entry != null && !entry.isExpired()) {
-            return entry.value();
-        }
-        return null;
-    }
-
-    @Override
-    public boolean contains(String key) {
-        Entry entry = store.get(key);
-        if (entry == null) {
-            return false;
-        }
-        if (entry.isExpired()) {
-            store.remove(key, entry);
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public Object putIfAbsent(String key, Object value, long ttlMillis) {
-        long expiresAt = ttlMillis > 0 ? System.currentTimeMillis() + ttlMillis : 0;
-        Object[] result = new Object[1];
-        store.compute(key, (k, current) -> {
-            if (current == null || current.isExpired()) {
-                return new Entry(value, expiresAt);
-            }
-            result[0] = current.value();
-            return current;
-        });
-        return result[0];
-    }
-
-    @Override
-    public int size() {
-        evictExpired();
-        return store.size();
-    }
-
-    @Override
-    public Set<String> keys() {
-        evictExpired();
-        return Set.copyOf(store.keySet());
-    }
-
-    private void evictExpired() {
-        store.entrySet().removeIf(e -> e.getValue().isExpired());
-    }
-
-    @Override
-    public void clear() {
-        store.clear();
-    }
-
-    @Override
-    public void start() {
-        // no-op
-    }
-
-    @Override
-    public void stop() {
-        store.clear();
-    }
-
-    private record Entry(Object value, long expiresAt) {
-
-        boolean isExpired() {
-            return expiresAt > 0 && System.currentTimeMillis() > expiresAt;
-        }
-    }
-}
diff --git a/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreBackend.java b/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreBackend.java
deleted file mode 100644
index 974f95e4f889..000000000000
--- a/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreBackend.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.camel.component.statestore;
-
-import java.util.Set;
-
-import org.apache.camel.Service;
-
-/**
- * Interface for pluggable state store backends.
- *
- * @since 4.23
- */
-public interface StateStoreBackend extends Service {
-
-    /**
-     * Store a value with the given key and optional TTL.
-     *
-     * @param  key       the key
-     * @param  value     the value to store
-     * @param  ttlMillis time-to-live in milliseconds (0 = no expiry)
-     * @return           the previous value associated with the key, or null
-     */
-    Object put(String key, Object value, long ttlMillis);
-
-    /**
-     * Store a value only if the key does not already exist.
-     * <p>
-     * <b>Note:</b> The default implementation is not atomic. Implementations that require thread safety should override
-     * this method with an atomic version (e.g., using the backing store's native putIfAbsent).
-     *
-     * @param  key       the key
-     * @param  value     the value to store
-     * @param  ttlMillis time-to-live in milliseconds (0 = no expiry)
-     * @return           the existing value if the key already exists, or null if the value was stored
-     */
-    default Object putIfAbsent(String key, Object value, long ttlMillis) {
-        if (contains(key)) {
-            return get(key);
-        }
-        put(key, value, ttlMillis);
-        return null;
-    }
-
-    /**
-     * Retrieve the value associated with the given key.
-     *
-     * @param  key the key
-     * @return     the value, or null if not found or expired
-     */
-    Object get(String key);
-
-    /**
-     * Remove the value associated with the given key.
-     *
-     * @param  key the key
-     * @return     the removed value, or null if not found
-     */
-    Object delete(String key);
-
-    /**
-     * Check if a key exists in the store.
-     *
-     * @param  key the key
-     * @return     true if the key exists and has not expired
-     */
-    boolean contains(String key);
-
-    /**
-     * Return all keys in the store.
-     *
-     * @return a set of all keys
-     */
-    Set<String> keys();
-
-    /**
-     * Return the number of entries in the store.
-     *
-     * @return the number of entries
-     */
-    default int size() {
-        return keys().size();
-    }
-
-    /**
-     * Remove all entries from the store.
-     */
-    void clear();
-}
diff --git a/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreComponent.java b/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreComponent.java
index 33bdb526a837..ca7dc43d56f4 100644
--- a/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreComponent.java
+++ b/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreComponent.java
@@ -21,13 +21,16 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.camel.Endpoint;
+import org.apache.camel.spi.KeyValueRepository;
 import org.apache.camel.spi.annotations.Component;
 import org.apache.camel.support.DefaultComponent;
+import org.apache.camel.support.MemoryKeyValueRepository;
+import org.apache.camel.support.service.ServiceHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * The State Store component provides a simple, unified key-value store API with pluggable backends.
+ * The State Store component provides a simple, unified key-value store API backed by a {@link KeyValueRepository}.
  *
  * @since 4.23
  */
@@ -36,7 +39,7 @@ public class StateStoreComponent extends DefaultComponent {
 
     private static final Logger LOG = LoggerFactory.getLogger(StateStoreComponent.class);
 
-    private final ConcurrentHashMap<String, StateStoreBackend> backends = new ConcurrentHashMap<>();
+    private final ConcurrentHashMap<String, KeyValueRepository> backends = new ConcurrentHashMap<>();
 
     @Override
     protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
@@ -51,9 +54,9 @@ public class StateStoreComponent extends DefaultComponent {
      * already exists for this store name, subsequent calls return the existing one regardless of the explicit backend
      * passed.
      */
-    StateStoreBackend getOrCreateBackend(String storeName, StateStoreBackend explicitBackend) {
+    KeyValueRepository getOrCreateBackend(String storeName, KeyValueRepository explicitBackend) {
         if (explicitBackend != null) {
-            StateStoreBackend existing = backends.putIfAbsent(storeName, explicitBackend);
+            KeyValueRepository existing = backends.putIfAbsent(storeName, explicitBackend);
             if (existing != null) {
                 if (existing != explicitBackend) {
                     LOG.warn("Store '{}' already has a backend ({}). Ignoring explicit backend=# reference ({}).",
@@ -61,31 +64,31 @@ public class StateStoreComponent extends DefaultComponent {
                 }
                 return existing;
             }
-            explicitBackend.start();
+            ServiceHelper.startService(explicitBackend);
             return explicitBackend;
         }
         return backends.computeIfAbsent(storeName, k -> {
-            // Auto-discover a StateStoreBackend from the registry
-            Set<StateStoreBackend> found = getCamelContext().getRegistry().findByType(StateStoreBackend.class);
-            StateStoreBackend backend;
+            // Auto-discover a KeyValueRepository from the registry
+            Set<KeyValueRepository> found = getCamelContext().getRegistry().findByType(KeyValueRepository.class);
+            KeyValueRepository backend;
             if (found.size() == 1) {
                 backend = found.iterator().next();
-                LOG.debug("Auto-discovered StateStoreBackend '{}' for store '{}'",
+                LOG.debug("Auto-discovered KeyValueRepository '{}' for store '{}'",
                         backend.getClass().getSimpleName(), storeName);
             } else {
                 if (found.size() > 1) {
                     LOG.warn(
-                            "Found {} StateStoreBackend instances in the registry for store '{}'. "
-                             + "Cannot auto-select — falling back to InMemoryStateStoreBackend. "
+                            "Found {} KeyValueRepository instances in the registry for store '{}'. "
+                             + "Cannot auto-select — falling back to MemoryKeyValueRepository. "
                              + "Use an explicit backend=# reference to choose one.",
                             found.size(), storeName);
                 } else {
-                    LOG.info("No StateStoreBackend found in the registry for store '{}'. Using InMemoryStateStoreBackend.",
+                    LOG.info("No KeyValueRepository found in the registry for store '{}'. Using MemoryKeyValueRepository.",
                             storeName);
                 }
-                backend = new InMemoryStateStoreBackend();
+                backend = new MemoryKeyValueRepository();
             }
-            backend.start();
+            ServiceHelper.startService(backend);
             return backend;
         });
     }
@@ -93,9 +96,9 @@ public class StateStoreComponent extends DefaultComponent {
     @Override
     protected void doStop() throws Exception {
         Exception firstException = null;
-        for (StateStoreBackend backend : backends.values()) {
+        for (KeyValueRepository backend : backends.values()) {
             try {
-                backend.stop();
+                ServiceHelper.stopService(backend);
             } catch (Exception e) {
                 LOG.warn("Error stopping backend: {}", e.getMessage(), e);
                 if (firstException == null) {
diff --git a/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreEndpoint.java b/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreEndpoint.java
index 9b4fc426ec43..62747afce2e9 100644
--- a/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreEndpoint.java
+++ b/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreEndpoint.java
@@ -20,6 +20,7 @@ import org.apache.camel.Category;
 import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
+import org.apache.camel.spi.KeyValueRepository;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
@@ -27,7 +28,7 @@ import org.apache.camel.spi.UriPath;
 import org.apache.camel.support.DefaultEndpoint;
 
 /**
- * Perform key-value operations against a pluggable state store backend.
+ * Perform key-value operations against a pluggable {@link KeyValueRepository} backend.
  *
  * @since 4.23
  */
@@ -44,9 +45,9 @@ public class StateStoreEndpoint extends DefaultEndpoint {
     @UriParam(description = "The default operation to perform", enums = "put,putIfAbsent,get,delete,contains,keys,size,clear")
     private StateStoreOperations operation;
 
-    @UriParam(description = "The backend to use. If not set, auto-discovers a single StateStoreBackend from the registry, or falls back to an in-memory store.",
+    @UriParam(description = "The backend to use. If not set, auto-discovers a single KeyValueRepository from the registry, or falls back to an in-memory store.",
               label = "advanced")
-    private StateStoreBackend backend;
+    private KeyValueRepository backend;
 
     @UriParam(description = "Time-to-live in milliseconds for entries. 0 means no expiry.", defaultValue = "0")
     private long ttl;
@@ -88,11 +89,11 @@ public class StateStoreEndpoint extends DefaultEndpoint {
         this.operation = operation;
     }
 
-    public StateStoreBackend getBackend() {
+    public KeyValueRepository getBackend() {
         return backend;
     }
 
-    public void setBackend(StateStoreBackend backend) {
+    public void setBackend(KeyValueRepository backend) {
         this.backend = backend;
     }
 
diff --git a/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreProducer.java b/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreProducer.java
index 4c8a23128595..4f4a175c6b11 100644
--- a/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreProducer.java
+++ b/components/camel-state-store/camel-state-store/src/main/java/org/apache/camel/component/statestore/StateStoreProducer.java
@@ -20,10 +20,11 @@ import java.util.Arrays;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
+import org.apache.camel.spi.KeyValueRepository;
 import org.apache.camel.support.DefaultProducer;
 
 /**
- * Producer for the State Store component that performs key-value operations.
+ * Producer for the State Store component that performs key-value operations against a {@link KeyValueRepository}.
  *
  * @since 4.23
  */
@@ -44,7 +45,7 @@ public class StateStoreProducer extends DefaultProducer {
                     "No operation specified. Set the operation via URI option or header " + StateStoreConstants.OPERATION);
         }
 
-        StateStoreBackend backend = endpoint.getBackend();
+        KeyValueRepository backend = endpoint.getBackend();
         long ttl = determineTtl(exchange);
         Message message = exchange.getMessage();
 
diff --git a/components/camel-state-store/camel-state-store/src/test/java/org/apache/camel/component/statestore/StateStoreAutoDiscoveryTest.java b/components/camel-state-store/camel-state-store/src/test/java/org/apache/camel/component/statestore/StateStoreAutoDiscoveryTest.java
index f16c429d950c..8f1cfba27b4b 100644
--- a/components/camel-state-store/camel-state-store/src/test/java/org/apache/camel/component/statestore/StateStoreAutoDiscoveryTest.java
+++ b/components/camel-state-store/camel-state-store/src/test/java/org/apache/camel/component/statestore/StateStoreAutoDiscoveryTest.java
@@ -20,21 +20,23 @@ import java.util.Map;
 
 import org.apache.camel.BindToRegistry;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.KeyValueRepository;
+import org.apache.camel.support.MemoryKeyValueRepository;
 import org.apache.camel.test.junit5.CamelTestSupport;
 import org.junit.jupiter.api.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 /**
- * Tests that a single {@link StateStoreBackend} in the registry is auto-discovered when no explicit backend is
+ * Tests that a single {@link KeyValueRepository} in the registry is auto-discovered when no explicit backend is
  * specified on the endpoint.
  */
 class StateStoreAutoDiscoveryTest extends CamelTestSupport {
 
-    private final TrackingInMemoryBackend trackingBackend = new TrackingInMemoryBackend();
+    private final TrackingKeyValueRepository trackingBackend = new TrackingKeyValueRepository();
 
     @BindToRegistry("myBackend")
-    public StateStoreBackend getBackend() {
+    public KeyValueRepository getBackend() {
         return trackingBackend;
     }
 
@@ -50,8 +52,8 @@ class StateStoreAutoDiscoveryTest extends CamelTestSupport {
                 Map.of(StateStoreConstants.KEY, "key1"));
         assertThat(result).isEqualTo("hello");
 
-        // Verify our tracking backend was used, not the default InMemoryStateStoreBackend
-        assertThat(trackingBackend).isInstanceOf(TrackingInMemoryBackend.class);
+        // Verify our tracking backend was used, not the default MemoryKeyValueRepository
+        assertThat(trackingBackend).isInstanceOf(TrackingKeyValueRepository.class);
         assertThat(trackingBackend.keys()).containsExactly("key1");
     }
 
@@ -68,8 +70,8 @@ class StateStoreAutoDiscoveryTest extends CamelTestSupport {
     }
 
     /**
-     * A simple wrapper around InMemoryStateStoreBackend to verify it was used instead of a fresh default instance.
+     * A simple wrapper around MemoryKeyValueRepository to verify it was used instead of a fresh default instance.
      */
-    static class TrackingInMemoryBackend extends InMemoryStateStoreBackend {
+    static class TrackingKeyValueRepository extends MemoryKeyValueRepository {
     }
 }
diff --git a/components/camel-state-store/camel-state-store/src/test/java/org/apache/camel/component/statestore/StateStoreMultiBackendFallbackTest.java b/components/camel-state-store/camel-state-store/src/test/java/org/apache/camel/component/statestore/StateStoreMultiBackendFallbackTest.java
index 1795462e00dc..516a80154e00 100644
--- a/components/camel-state-store/camel-state-store/src/test/java/org/apache/camel/component/statestore/StateStoreMultiBackendFallbackTest.java
+++ b/components/camel-state-store/camel-state-store/src/test/java/org/apache/camel/component/statestore/StateStoreMultiBackendFallbackTest.java
@@ -20,27 +20,29 @@ import java.util.Map;
 
 import org.apache.camel.BindToRegistry;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.support.MemoryKeyValueRepository;
 import org.apache.camel.test.junit5.CamelTestSupport;
 import org.junit.jupiter.api.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
 /**
- * Tests that when multiple {@link StateStoreBackend} instances are in the registry and no explicit backend is
- * specified, the component falls back to {@link InMemoryStateStoreBackend} and logs a warning.
+ * Tests that when multiple {@link org.apache.camel.spi.KeyValueRepository} instances are in the registry and no
+ * explicit backend is specified, the component falls back to a fresh {@link MemoryKeyValueRepository} and logs a
+ * warning.
  */
 class StateStoreMultiBackendFallbackTest extends CamelTestSupport {
 
     @BindToRegistry("backend1")
-    private final InMemoryStateStoreBackend backendOne = new InMemoryStateStoreBackend();
+    private final MemoryKeyValueRepository backendOne = new MemoryKeyValueRepository();
 
     @BindToRegistry("backend2")
-    private final InMemoryStateStoreBackend backendTwo = new InMemoryStateStoreBackend();
+    private final MemoryKeyValueRepository backendTwo = new MemoryKeyValueRepository();
 
     @Test
     void testFallsBackToInMemoryWhenMultipleBackends() {
         // With two backends in the registry and no explicit reference,
-        // auto-discovery should fall back to a fresh InMemoryStateStoreBackend
+        // auto-discovery should fall back to a fresh MemoryKeyValueRepository
         Object previous = template.requestBodyAndHeaders(
                 "direct:put", "hello",
                 Map.of(StateStoreConstants.KEY, "key1"));
diff --git a/components/camel-state-store/pom.xml b/components/camel-state-store/pom.xml
index 2e28ec5e33c4..dcfa858ff763 100644
--- a/components/camel-state-store/pom.xml
+++ b/components/camel-state-store/pom.xml
@@ -34,9 +34,6 @@
 
     <modules>
         <module>camel-state-store</module>
-        <module>camel-state-store-caffeine</module>
-        <module>camel-state-store-redis</module>
-        <module>camel-state-store-infinispan</module>
     </modules>
 
 </project>
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/KeyValueRepository.java b/core/camel-api/src/main/java/org/apache/camel/spi/KeyValueRepository.java
new file mode 100644
index 000000000000..cd7d6f8a1ac6
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/KeyValueRepository.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.spi;
+
+import java.util.Set;
+
+import org.apache.camel.Service;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * A generic key-value repository SPI that provides a unified abstraction over various state stores.
+ * <p/>
+ * This interface can be used as the single underlying storage mechanism for multiple Camel patterns, including:
+ * <ul>
+ * <li><b>Idempotent Consumer</b> -- via {@code KeyValueIdempotentRepository} adapter</li>
+ * <li><b>Aggregation</b> -- via {@code KeyValueAggregationRepository} adapter</li>
+ * </ul>
+ * Instead of implementing both {@link IdempotentRepository} and {@link AggregationRepository} separately for each
+ * storage technology (Redis, Hazelcast, Infinispan, JDBC, etc.), a single {@code KeyValueRepository} implementation can
+ * be wrapped by the appropriate adapter.
+ * <p/>
+ * Implementations must be thread-safe. Entries may optionally have a time-to-live (TTL); a TTL of {@code 0} or less
+ * means the entry does not expire.
+ *
+ * @since 4.23
+ */
+public interface KeyValueRepository extends Service {
+
+    /**
+     * Retrieves the value associated with the given key.
+     *
+     * @param  key the key to look up
+     * @return     the value, or {@code null} if the key is not present or has expired
+     */
+    @Nullable
+    Object get(String key);
+
+    /**
+     * Stores a value under the given key with an optional time-to-live.
+     *
+     * @param  key       the key
+     * @param  value     the value to store
+     * @param  ttlMillis the time-to-live in milliseconds; {@code 0} or negative means no expiration
+     * @return           the previous value associated with the key, or {@code null} if there was no mapping
+     */
+    @Nullable
+    Object put(String key, Object value, long ttlMillis);
+
+    /**
+     * Removes the entry for the given key.
+     *
+     * @param  key the key to remove
+     * @return     the previous value associated with the key, or {@code null} if no mapping existed
+     */
+    @Nullable
+    Object delete(String key);
+
+    /**
+     * Tests whether the repository contains a non-expired entry for the given key.
+     *
+     * @param  key the key to test
+     * @return     {@code true} if the key is present and has not expired
+     */
+    boolean contains(String key);
+
+    /**
+     * Returns the set of all non-expired keys in the repository.
+     *
+     * @return a snapshot of the current key set
+     */
+    Set<String> keys();
+
+    /**
+     * Removes all entries from the repository.
+     */
+    void clear();
+
+    /**
+     * Stores the value under the given key only if no non-expired mapping already exists.
+     * <p/>
+     * The default implementation is not atomic. Implementations backed by stores that support atomic compare-and-set
+     * operations should override this method for better concurrency guarantees.
+     *
+     * @param  key       the key
+     * @param  value     the value to store
+     * @param  ttlMillis the time-to-live in milliseconds; {@code 0} or negative means no expiration
+     * @return           the existing value if the key was already present, or {@code null} if the put succeeded
+     */
+    @Nullable
+    default Object putIfAbsent(String key, Object value, long ttlMillis) {
+        Object existing = get(key);
+        if (existing != null) {
+            return existing;
+        }
+        put(key, value, ttlMillis);
+        return null;
+    }
+
+    /**
+     * Returns the number of non-expired entries in the repository.
+     *
+     * @return the entry count
+     */
+    default int size() {
+        return keys().size();
+    }
+}
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/AggregateProcessor.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/AggregateProcessor.java
index 7bc663d7283b..1f5d8b856f41 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/AggregateProcessor.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/aggregate/AggregateProcessor.java
@@ -54,6 +54,7 @@ import org.apache.camel.processor.BaseProcessorSupport;
 import org.apache.camel.spi.AggregationRepository;
 import org.apache.camel.spi.ExceptionHandler;
 import org.apache.camel.spi.IdAware;
+import org.apache.camel.spi.KeyValueRepository;
 import org.apache.camel.spi.OptimisticLockingAggregationRepository;
 import org.apache.camel.spi.ReactiveExecutor;
 import org.apache.camel.spi.RecoverableAggregationRepository;
@@ -63,6 +64,7 @@ import org.apache.camel.spi.StepIdAware;
 import org.apache.camel.spi.Synchronization;
 import org.apache.camel.support.DefaultTimeoutMap;
 import org.apache.camel.support.ExchangeHelper;
+import org.apache.camel.support.KeyValueAggregationRepository;
 import org.apache.camel.support.LRUCacheFactory;
 import org.apache.camel.support.LoggingExceptionHandler;
 import org.apache.camel.support.NoLock;
@@ -1617,8 +1619,15 @@ public class AggregateProcessor extends BaseProcessorSupport
         }
 
         if (aggregationRepository == null) {
-            aggregationRepository = new MemoryAggregationRepository(optimisticLocking);
-            LOG.info("Defaulting to MemoryAggregationRepository");
+            // Auto-discover a KeyValueRepository from the registry and wrap it
+            KeyValueRepository kvRepo = camelContext.getRegistry().findSingleByType(KeyValueRepository.class);
+            if (kvRepo != null) {
+                aggregationRepository = new KeyValueAggregationRepository(kvRepo);
+                LOG.info("Auto-discovered KeyValueRepository from registry, wrapping as AggregationRepository");
+            } else {
+                aggregationRepository = new MemoryAggregationRepository(optimisticLocking);
+                LOG.info("Defaulting to MemoryAggregationRepository");
+            }
         }
 
         if (optimisticLocking) {
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/IdempotentConsumerReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/IdempotentConsumerReifier.java
index 24e163a2ca83..5773d481f287 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/IdempotentConsumerReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/IdempotentConsumerReifier.java
@@ -23,10 +23,16 @@ import org.apache.camel.model.IdempotentConsumerDefinition;
 import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.processor.idempotent.IdempotentConsumer;
 import org.apache.camel.spi.IdempotentRepository;
+import org.apache.camel.spi.KeyValueRepository;
+import org.apache.camel.support.KeyValueIdempotentRepository;
 import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class IdempotentConsumerReifier extends ExpressionReifier<IdempotentConsumerDefinition> {
 
+    private static final Logger LOG = LoggerFactory.getLogger(IdempotentConsumerReifier.class);
+
     public IdempotentConsumerReifier(Route route, ProcessorDefinition<?> definition) {
         super(route, IdempotentConsumerDefinition.class.cast(definition));
     }
@@ -54,9 +60,13 @@ public class IdempotentConsumerReifier extends ExpressionReifier<IdempotentConsu
     }
 
     /**
-     * Strategy method to resolve the {@link org.apache.camel.spi.IdempotentRepository} to use
+     * Strategy method to resolve the {@link org.apache.camel.spi.IdempotentRepository} to use.
+     * <p/>
+     * If no explicit {@link IdempotentRepository} is configured (neither as a bean reference nor inline), this method
+     * falls back to looking up a {@link KeyValueRepository} from the Camel registry and wrapping it in a
+     * {@link KeyValueIdempotentRepository} adapter.
      *
-     * @return the repository
+     * @return the repository, or {@code null} if none could be resolved
      */
     protected <T> IdempotentRepository resolveIdempotentRepository() {
         IdempotentRepository repo = definition.getIdempotentRepositoryBean();
@@ -64,6 +74,14 @@ public class IdempotentConsumerReifier extends ExpressionReifier<IdempotentConsu
         if (repo == null && ref != null) {
             repo = mandatoryLookup(ref, IdempotentRepository.class);
         }
+        if (repo == null) {
+            // Fallback: auto-discover a KeyValueRepository from the registry
+            KeyValueRepository kvRepo = camelContext.getRegistry().findSingleByType(KeyValueRepository.class);
+            if (kvRepo != null) {
+                LOG.info("Auto-discovered KeyValueRepository from registry, wrapping as IdempotentRepository");
+                repo = new KeyValueIdempotentRepository(kvRepo);
+            }
+        }
         return repo;
     }
 }
diff --git a/core/camel-core/src/test/java/org/apache/camel/support/KeyValueAggregationRepositoryTest.java b/core/camel-core/src/test/java/org/apache/camel/support/KeyValueAggregationRepositoryTest.java
new file mode 100644
index 000000000000..4debfc8d8ad7
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/support/KeyValueAggregationRepositoryTest.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.support;
+
+import java.util.Set;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class KeyValueAggregationRepositoryTest {
+
+    private CamelContext camelContext;
+    private MemoryKeyValueRepository kvRepository;
+    private KeyValueAggregationRepository aggregationRepository;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        camelContext = new DefaultCamelContext();
+        camelContext.start();
+
+        kvRepository = new MemoryKeyValueRepository();
+        kvRepository.start();
+
+        aggregationRepository = new KeyValueAggregationRepository(kvRepository);
+        aggregationRepository.setCamelContext(camelContext);
+        aggregationRepository.start();
+    }
+
+    @AfterEach
+    void tearDown() throws Exception {
+        aggregationRepository.stop();
+        camelContext.stop();
+    }
+
+    @Test
+    void testAddAndGet() {
+        Exchange exchange = createExchange("Hello World");
+
+        aggregationRepository.add(camelContext, "key1", exchange);
+
+        Exchange retrieved = aggregationRepository.get(camelContext, "key1");
+        assertThat(retrieved).isNotNull();
+        assertThat(retrieved.getIn().getBody(String.class)).isEqualTo("Hello World");
+    }
+
+    @Test
+    void testGetMissingKeyReturnsNull() {
+        Exchange retrieved = aggregationRepository.get(camelContext, "nonexistent");
+        assertThat(retrieved).isNull();
+    }
+
+    @Test
+    void testAddReturnsOldExchange() {
+        Exchange first = createExchange("First");
+        Exchange second = createExchange("Second");
+
+        Exchange oldFromFirst = aggregationRepository.add(camelContext, "key1", first);
+        assertThat(oldFromFirst).isNull();
+
+        Exchange oldFromSecond = aggregationRepository.add(camelContext, "key1", second);
+        assertThat(oldFromSecond).isNotNull();
+        assertThat(oldFromSecond.getIn().getBody(String.class)).isEqualTo("First");
+
+        // Current value should be the second exchange
+        Exchange current = aggregationRepository.get(camelContext, "key1");
+        assertThat(current.getIn().getBody(String.class)).isEqualTo("Second");
+    }
+
+    @Test
+    void testRemove() {
+        Exchange exchange = createExchange("Hello");
+        aggregationRepository.add(camelContext, "key1", exchange);
+
+        aggregationRepository.remove(camelContext, "key1", exchange);
+
+        assertThat(aggregationRepository.get(camelContext, "key1")).isNull();
+    }
+
+    @Test
+    void testGetKeys() {
+        aggregationRepository.add(camelContext, "key1", createExchange("One"));
+        aggregationRepository.add(camelContext, "key2", createExchange("Two"));
+        aggregationRepository.add(camelContext, "key3", createExchange("Three"));
+
+        Set<String> keys = aggregationRepository.getKeys();
+
+        assertThat(keys).containsExactlyInAnyOrder("key1", "key2", "key3");
+    }
+
+    @Test
+    void testGetKeysExcludesCompletedEntries() {
+        Exchange ex1 = createExchange("One");
+        Exchange ex2 = createExchange("Two");
+
+        aggregationRepository.add(camelContext, "key1", ex1);
+        aggregationRepository.add(camelContext, "key2", ex2);
+
+        // Remove key1 (moves to completed for recovery)
+        aggregationRepository.remove(camelContext, "key1", ex1);
+
+        Set<String> keys = aggregationRepository.getKeys();
+
+        // Only active aggregates should be returned
+        assertThat(keys).containsExactly("key2");
+    }
+
+    @Test
+    void testConfirmRemovesCompletedEntry() {
+        Exchange exchange = createExchange("Hello");
+        String exchangeId = exchange.getExchangeId();
+
+        aggregationRepository.add(camelContext, "key1", exchange);
+        aggregationRepository.remove(camelContext, "key1", exchange);
+
+        // The exchange should be recoverable before confirmation
+        Exchange recovered = aggregationRepository.recover(camelContext, exchangeId);
+        assertThat(recovered).isNotNull();
+
+        // After confirmation, it should no longer be recoverable
+        aggregationRepository.confirm(camelContext, exchangeId);
+        assertThat(aggregationRepository.recover(camelContext, exchangeId)).isNull();
+    }
+
+    @Test
+    void testScanReturnsCompletedExchangeIds() {
+        Exchange ex1 = createExchange("One");
+        Exchange ex2 = createExchange("Two");
+
+        aggregationRepository.add(camelContext, "key1", ex1);
+        aggregationRepository.add(camelContext, "key2", ex2);
+
+        // Remove both (move to completed)
+        aggregationRepository.remove(camelContext, "key1", ex1);
+        aggregationRepository.remove(camelContext, "key2", ex2);
+
+        Set<String> scanned = aggregationRepository.scan(camelContext);
+
+        assertThat(scanned).containsExactlyInAnyOrder(ex1.getExchangeId(), ex2.getExchangeId());
+    }
+
+    @Test
+    void testRecoverWithRecoveryDisabled() {
+        aggregationRepository.setUseRecovery(false);
+
+        Exchange exchange = createExchange("Hello");
+        aggregationRepository.add(camelContext, "key1", exchange);
+        aggregationRepository.remove(camelContext, "key1", exchange);
+
+        assertThat(aggregationRepository.recover(camelContext, exchange.getExchangeId())).isNull();
+    }
+
+    @Test
+    void testRecoverySettings() {
+        aggregationRepository.setRecoveryInterval(10000);
+        assertThat(aggregationRepository.getRecoveryInterval()).isEqualTo(10000);
+
+        aggregationRepository.setMaximumRedeliveries(5);
+        assertThat(aggregationRepository.getMaximumRedeliveries()).isEqualTo(5);
+
+        aggregationRepository.setDeadLetterUri("mock:dead");
+        assertThat(aggregationRepository.getDeadLetterUri()).isEqualTo("mock:dead");
+
+        aggregationRepository.setUseRecovery(false);
+        assertThat(aggregationRepository.isUseRecovery()).isFalse();
+    }
+
+    @Test
+    void testExchangeHeadersArePreserved() {
+        Exchange exchange = createExchange("Body");
+        exchange.getIn().setHeader("myHeader", "headerValue");
+        exchange.getIn().setHeader("myNumber", 42);
+
+        aggregationRepository.add(camelContext, "key1", exchange);
+
+        Exchange retrieved = aggregationRepository.get(camelContext, "key1");
+        assertThat(retrieved.getIn().getHeader("myHeader", String.class)).isEqualTo("headerValue");
+        assertThat(retrieved.getIn().getHeader("myNumber", Integer.class)).isEqualTo(42);
+    }
+
+    @Test
+    void testFactoryMethod() {
+        KeyValueAggregationRepository created
+                = KeyValueAggregationRepository.keyValueAggregationRepository(kvRepository);
+
+        assertThat(created).isNotNull();
+        assertThat(created.getRepository()).isSameAs(kvRepository);
+    }
+
+    private Exchange createExchange(String body) {
+        Exchange exchange = new DefaultExchange(camelContext);
+        exchange.getIn().setBody(body);
+        return exchange;
+    }
+}
diff --git a/core/camel-support/pom.xml b/core/camel-support/pom.xml
index 1d41d48c2436..a4c1793693ff 100644
--- a/core/camel-support/pom.xml
+++ b/core/camel-support/pom.xml
@@ -71,6 +71,17 @@
             <artifactId>junit-jupiter</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.awaitility</groupId>
+            <artifactId>awaitility</artifactId>
+            <version>${awaitility-version}</version>
+            <scope>test</scope>
+        </dependency>
 
         <!-- logging -->
         <dependency>
diff --git a/core/camel-support/src/generated/java/org/apache/camel/support/MemoryKeyValueRepositoryConfigurer.java b/core/camel-support/src/generated/java/org/apache/camel/support/MemoryKeyValueRepositoryConfigurer.java
new file mode 100644
index 000000000000..c78589d14375
--- /dev/null
+++ b/core/camel-support/src/generated/java/org/apache/camel/support/MemoryKeyValueRepositoryConfigurer.java
@@ -0,0 +1,37 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.support;
+
+import javax.annotation.processing.Generated;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.support.MemoryKeyValueRepository;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.GenerateConfigurerMojo")
+@SuppressWarnings("unchecked")
+public class MemoryKeyValueRepositoryConfigurer extends org.apache.camel.support.component.PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
+        return false;
+    }
+
+    @Override
+    public Class<?> getOptionType(String name, boolean ignoreCase) {
+        return null;
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        return null;
+    }
+}
+
diff --git a/core/camel-support/src/generated/resources/META-INF/services/org/apache/camel/bean.properties b/core/camel-support/src/generated/resources/META-INF/services/org/apache/camel/bean.properties
index 6ab75a7fb32f..2b3850b73b6b 100644
--- a/core/camel-support/src/generated/resources/META-INF/services/org/apache/camel/bean.properties
+++ b/core/camel-support/src/generated/resources/META-INF/services/org/apache/camel/bean.properties
@@ -1,5 +1,5 @@
 # Generated by camel build tools - do NOT edit this file!
-bean=AcceptAllHeaderFilterStrategy DefaultHeaderFilterStrategy FileIdempotentRepository MemoryIdempotentRepository ThrottlingExceptionRoutePolicy ThrottlingInflightRoutePolicy
+bean=AcceptAllHeaderFilterStrategy DefaultHeaderFilterStrategy FileIdempotentRepository MemoryIdempotentRepository MemoryKeyValueRepository ThrottlingExceptionRoutePolicy ThrottlingInflightRoutePolicy
 groupId=org.apache.camel
 artifactId=camel-support
 version=4.23.0-SNAPSHOT
diff --git a/core/camel-support/src/generated/resources/META-INF/services/org/apache/camel/bean/MemoryKeyValueRepository.json b/core/camel-support/src/generated/resources/META-INF/services/org/apache/camel/bean/MemoryKeyValueRepository.json
new file mode 100644
index 000000000000..4630dec20634
--- /dev/null
+++ b/core/camel-support/src/generated/resources/META-INF/services/org/apache/camel/bean/MemoryKeyValueRepository.json
@@ -0,0 +1,15 @@
+{
+  "bean": {
+    "kind": "bean",
+    "name": "MemoryKeyValueRepository",
+    "javaType": "org.apache.camel.support.MemoryKeyValueRepository",
+    "interfaceType": "org.apache.camel.spi.KeyValueRepository",
+    "title": "Memory Key Value Repository",
+    "description": "An in-memory KeyValueRepository with optional TTL support.",
+    "deprecated": false,
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-support",
+    "version": "4.23.0-SNAPSHOT"
+  }
+}
+
diff --git a/core/camel-support/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.support.MemoryKeyValueRepository b/core/camel-support/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.support.MemoryKeyValueRepository
new file mode 100644
index 000000000000..8ef5d9621fee
--- /dev/null
+++ b/core/camel-support/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.support.MemoryKeyValueRepository
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.support.MemoryKeyValueRepositoryConfigurer
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/KeyValueAggregationRepository.java b/core/camel-support/src/main/java/org/apache/camel/support/KeyValueAggregationRepository.java
new file mode 100644
index 000000000000..da6dbb6ac269
--- /dev/null
+++ b/core/camel-support/src/main/java/org/apache/camel/support/KeyValueAggregationRepository.java
@@ -0,0 +1,238 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.support;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.Exchange;
+import org.apache.camel.spi.KeyValueRepository;
+import org.apache.camel.spi.RecoverableAggregationRepository;
+import org.apache.camel.support.service.ServiceHelper;
+import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An adapter that implements {@link RecoverableAggregationRepository} by delegating to a {@link KeyValueRepository}.
+ * <p/>
+ * Exchanges are serialized and deserialized using {@link DefaultExchangeHolder}. Active (in-progress) aggregates are
+ * stored under the correlation key. Completed-but-unconfirmed aggregates (for recovery) are stored under a separate key
+ * derived from the exchange ID.
+ * <p/>
+ * This allows any {@link KeyValueRepository} implementation to be used as an aggregation repository without
+ * implementing the {@link org.apache.camel.spi.AggregationRepository} interface directly.
+ *
+ * @since 4.23
+ */
+public class KeyValueAggregationRepository extends ServiceSupport
+        implements RecoverableAggregationRepository, CamelContextAware {
+
+    private static final Logger LOG = LoggerFactory.getLogger(KeyValueAggregationRepository.class);
+
+    /**
+     * Prefix used to namespace active aggregate entries, preventing key collisions when this adapter shares the same
+     * {@link KeyValueRepository} with other adapters (e.g. {@link KeyValueIdempotentRepository}).
+     */
+    private static final String AGGREGATE_PREFIX = "aggregate:";
+
+    /**
+     * Prefix used to separate completed (pending confirmation) entries from active aggregates in the underlying store.
+     */
+    private static final String COMPLETED_PREFIX = "completed:";
+
+    private final KeyValueRepository repository;
+    private CamelContext camelContext;
+    private boolean useRecovery = true;
+    private String deadLetterUri;
+    private long recoveryInterval = 5000;
+    private int maximumRedeliveries = 3;
+    private boolean allowSerializedHeaders;
+
+    /**
+     * Creates an aggregation repository adapter backed by the given key-value repository.
+     *
+     * @param repository the underlying key-value repository; must not be {@code null}
+     */
+    public KeyValueAggregationRepository(KeyValueRepository repository) {
+        ObjectHelper.notNull(repository, "repository");
+        this.repository = repository;
+    }
+
+    /**
+     * Creates a new {@link KeyValueAggregationRepository} wrapping the given {@link KeyValueRepository}.
+     *
+     * @param  repository the underlying key-value repository
+     * @return            the adapter
+     */
+    public static KeyValueAggregationRepository keyValueAggregationRepository(KeyValueRepository repository) {
+        return new KeyValueAggregationRepository(repository);
+    }
+
+    @Override
+    public Exchange add(CamelContext camelContext, String key, Exchange exchange) {
+        LOG.trace("Adding an Exchange with ID {} for key {}", exchange.getExchangeId(), key);
+        DefaultExchangeHolder newHolder = DefaultExchangeHolder.marshal(exchange, true, allowSerializedHeaders);
+        DefaultExchangeHolder oldHolder = (DefaultExchangeHolder) repository.put(AGGREGATE_PREFIX + key, newHolder, 0);
+        return unmarshallExchange(camelContext, oldHolder);
+    }
+
+    @Override
+    public Exchange get(CamelContext camelContext, String key) {
+        return unmarshallExchange(camelContext, (DefaultExchangeHolder) repository.get(AGGREGATE_PREFIX + key));
+    }
+
+    @Override
+    public void remove(CamelContext camelContext, String key, Exchange exchange) {
+        LOG.trace("Removing an Exchange with ID {} for key {}", exchange.getExchangeId(), key);
+        DefaultExchangeHolder holder = (DefaultExchangeHolder) repository.delete(AGGREGATE_PREFIX + key);
+        if (useRecovery && holder != null) {
+            // Store under the exchangeId for potential recovery
+            LOG.trace("Moving Exchange with ID {} to completed (pending confirmation)", exchange.getExchangeId());
+            repository.put(COMPLETED_PREFIX + exchange.getExchangeId(), holder, 0);
+        }
+    }
+
+    @Override
+    public void confirm(CamelContext camelContext, String exchangeId) {
+        LOG.trace("Confirming an Exchange with ID {}", exchangeId);
+        repository.delete(COMPLETED_PREFIX + exchangeId);
+    }
+
+    @Override
+    public Set<String> getKeys() {
+        return Collections.unmodifiableSet(
+                repository.keys().stream()
+                        .filter(k -> k.startsWith(AGGREGATE_PREFIX))
+                        .map(k -> k.substring(AGGREGATE_PREFIX.length()))
+                        .collect(Collectors.toSet()));
+    }
+
+    @Override
+    public Set<String> scan(CamelContext camelContext) {
+        LOG.trace("Scanning for exchanges to recover in {} context", camelContext.getName());
+        Set<String> scanned = repository.keys().stream()
+                .filter(k -> k.startsWith(COMPLETED_PREFIX))
+                .map(k -> k.substring(COMPLETED_PREFIX.length()))
+                .collect(Collectors.toUnmodifiableSet());
+        LOG.trace("Found {} keys for exchanges to recover in {} context", scanned.size(), camelContext.getName());
+        return scanned;
+    }
+
+    @Override
+    public Exchange recover(CamelContext camelContext, String exchangeId) {
+        LOG.trace("Recovering an Exchange with ID {}", exchangeId);
+        if (!useRecovery) {
+            return null;
+        }
+        return unmarshallExchange(camelContext, (DefaultExchangeHolder) repository.get(COMPLETED_PREFIX + exchangeId));
+    }
+
+    @Override
+    public void setRecoveryInterval(long interval, TimeUnit timeUnit) {
+        this.recoveryInterval = timeUnit.toMillis(interval);
+    }
+
+    @Override
+    public void setRecoveryInterval(long interval) {
+        this.recoveryInterval = interval;
+    }
+
+    @Override
+    public long getRecoveryInterval() {
+        return recoveryInterval;
+    }
+
+    @Override
+    public void setUseRecovery(boolean useRecovery) {
+        this.useRecovery = useRecovery;
+    }
+
+    @Override
+    public boolean isUseRecovery() {
+        return useRecovery;
+    }
+
+    @Override
+    public void setDeadLetterUri(String deadLetterUri) {
+        this.deadLetterUri = deadLetterUri;
+    }
+
+    @Override
+    public String getDeadLetterUri() {
+        return deadLetterUri;
+    }
+
+    @Override
+    public void setMaximumRedeliveries(int maximumRedeliveries) {
+        this.maximumRedeliveries = maximumRedeliveries;
+    }
+
+    @Override
+    public int getMaximumRedeliveries() {
+        return maximumRedeliveries;
+    }
+
+    public boolean isAllowSerializedHeaders() {
+        return allowSerializedHeaders;
+    }
+
+    public void setAllowSerializedHeaders(boolean allowSerializedHeaders) {
+        this.allowSerializedHeaders = allowSerializedHeaders;
+    }
+
+    /**
+     * Returns the underlying {@link KeyValueRepository}.
+     */
+    public KeyValueRepository getRepository() {
+        return repository;
+    }
+
+    @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        ServiceHelper.startService(repository);
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        ServiceHelper.stopService(repository);
+    }
+
+    private Exchange unmarshallExchange(CamelContext camelContext, DefaultExchangeHolder holder) {
+        if (holder == null) {
+            return null;
+        }
+        Exchange exchange = new DefaultExchange(camelContext);
+        DefaultExchangeHolder.unmarshal(exchange, holder);
+        return exchange;
+    }
+}
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/KeyValueIdempotentRepository.java b/core/camel-support/src/main/java/org/apache/camel/support/KeyValueIdempotentRepository.java
new file mode 100644
index 000000000000..d08e4fc38418
--- /dev/null
+++ b/core/camel-support/src/main/java/org/apache/camel/support/KeyValueIdempotentRepository.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.support;
+
+import org.apache.camel.spi.IdempotentRepository;
+import org.apache.camel.spi.KeyValueRepository;
+import org.apache.camel.support.service.ServiceHelper;
+import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.util.ObjectHelper;
+
+/**
+ * An adapter that implements {@link IdempotentRepository} by delegating to a {@link KeyValueRepository}.
+ * <p/>
+ * This adapter uses {@link Boolean#TRUE} as the marker value stored in the underlying key-value repository. The key
+ * itself is the message identifier used for duplicate detection.
+ * <p/>
+ * This allows any {@link KeyValueRepository} implementation (e.g. backed by Redis, Infinispan, JDBC, etc.) to be used
+ * as an idempotent repository without implementing the {@link IdempotentRepository} interface directly.
+ *
+ * @since 4.23
+ */
+public class KeyValueIdempotentRepository extends ServiceSupport implements IdempotentRepository {
+
+    /**
+     * Prefix used to namespace idempotent entries, preventing key collisions when this adapter shares the same
+     * {@link KeyValueRepository} with other adapters (e.g. {@link KeyValueAggregationRepository}).
+     */
+    private static final String IDEMPOTENT_PREFIX = "idempotent:";
+
+    private final KeyValueRepository repository;
+
+    /**
+     * Creates an idempotent repository adapter backed by the given key-value repository.
+     *
+     * @param repository the underlying key-value repository; must not be {@code null}
+     */
+    public KeyValueIdempotentRepository(KeyValueRepository repository) {
+        ObjectHelper.notNull(repository, "repository");
+        this.repository = repository;
+    }
+
+    /**
+     * Creates a new {@link KeyValueIdempotentRepository} wrapping the given {@link KeyValueRepository}.
+     *
+     * @param  repository the underlying key-value repository
+     * @return            the adapter
+     */
+    public static KeyValueIdempotentRepository keyValueIdempotentRepository(KeyValueRepository repository) {
+        return new KeyValueIdempotentRepository(repository);
+    }
+
+    @Override
+    public boolean add(String key) {
+        // putIfAbsent returns null if the key was successfully added (not already present)
+        return repository.putIfAbsent(IDEMPOTENT_PREFIX + key, Boolean.TRUE, 0) == null;
+    }
+
+    @Override
+    public boolean contains(String key) {
+        return repository.contains(IDEMPOTENT_PREFIX + key);
+    }
+
+    @Override
+    public boolean remove(String key) {
+        return repository.delete(IDEMPOTENT_PREFIX + key) != null;
+    }
+
+    @Override
+    public boolean confirm(String key) {
+        // noop -- the key was already added
+        return true;
+    }
+
+    @Override
+    public void clear() {
+        // Only clear entries with our prefix to avoid affecting other adapters sharing the repository
+        for (String key : repository.keys()) {
+            if (key.startsWith(IDEMPOTENT_PREFIX)) {
+                repository.delete(key);
+            }
+        }
+    }
+
+    /**
+     * Returns the underlying {@link KeyValueRepository}.
+     */
+    public KeyValueRepository getRepository() {
+        return repository;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        ServiceHelper.startService(repository);
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        ServiceHelper.stopService(repository);
+    }
+}
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/MemoryKeyValueRepository.java b/core/camel-support/src/main/java/org/apache/camel/support/MemoryKeyValueRepository.java
new file mode 100644
index 000000000000..f32527ea9094
--- /dev/null
+++ b/core/camel-support/src/main/java/org/apache/camel/support/MemoryKeyValueRepository.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.support;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+import org.apache.camel.api.management.ManagedAttribute;
+import org.apache.camel.api.management.ManagedOperation;
+import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.spi.Configurer;
+import org.apache.camel.spi.KeyValueRepository;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.support.service.ServiceSupport;
+
+/**
+ * An in-memory implementation of {@link KeyValueRepository} backed by a {@link ConcurrentHashMap} with lazy TTL
+ * eviction.
+ * <p/>
+ * Expired entries are removed lazily on access ({@link #get}, {@link #contains}) and periodically during
+ * {@link #keys()} and {@link #size()} scans. This avoids the overhead of a background eviction thread while still
+ * ensuring that expired data is not returned.
+ *
+ * @since 4.23
+ */
+@Metadata(label = "bean",
+          description = "An in-memory KeyValueRepository with optional TTL support.",
+          annotations = { "interfaceName=org.apache.camel.spi.KeyValueRepository" })
+@Configurer(metadataOnly = true)
+@ManagedResource(description = "Memory based key-value repository")
+public class MemoryKeyValueRepository extends ServiceSupport implements KeyValueRepository {
+
+    private final ConcurrentHashMap<String, Entry> store = new ConcurrentHashMap<>();
+
+    /**
+     * Creates a new in-memory key-value repository.
+     */
+    public MemoryKeyValueRepository() {
+    }
+
+    @Override
+    @ManagedOperation(description = "Get value by key")
+    public Object get(String key) {
+        Entry entry = store.get(key);
+        if (entry == null) {
+            return null;
+        }
+        if (entry.isExpired()) {
+            store.remove(key, entry);
+            return null;
+        }
+        return entry.value();
+    }
+
+    @Override
+    @ManagedOperation(description = "Put a key-value pair with optional TTL")
+    public Object put(String key, Object value, long ttlMillis) {
+        long expiresAt = ttlMillis > 0 ? System.currentTimeMillis() + ttlMillis : Long.MAX_VALUE;
+        Entry previous = store.put(key, new Entry(value, expiresAt));
+        if (previous == null) {
+            return null;
+        }
+        if (previous.isExpired()) {
+            return null;
+        }
+        return previous.value();
+    }
+
+    @Override
+    @ManagedOperation(description = "Delete a key")
+    public Object delete(String key) {
+        Entry entry = store.remove(key);
+        if (entry == null) {
+            return null;
+        }
+        if (entry.isExpired()) {
+            return null;
+        }
+        return entry.value();
+    }
+
+    @Override
+    @ManagedOperation(description = "Check if key exists")
+    public boolean contains(String key) {
+        Entry entry = store.get(key);
+        if (entry == null) {
+            return false;
+        }
+        if (entry.isExpired()) {
+            store.remove(key, entry);
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public Set<String> keys() {
+        evictExpired();
+        return store.keySet().stream()
+                .filter(k -> {
+                    Entry e = store.get(k);
+                    return e != null && !e.isExpired();
+                })
+                .collect(Collectors.toUnmodifiableSet());
+    }
+
+    @Override
+    @ManagedOperation(description = "Clear all entries")
+    public void clear() {
+        store.clear();
+    }
+
+    @Override
+    public Object putIfAbsent(String key, Object value, long ttlMillis) {
+        long expiresAt = ttlMillis > 0 ? System.currentTimeMillis() + ttlMillis : Long.MAX_VALUE;
+        Entry newEntry = new Entry(value, expiresAt);
+        Entry existing = store.putIfAbsent(key, newEntry);
+        if (existing == null) {
+            return null;
+        }
+        if (existing.isExpired()) {
+            // Try to replace the expired entry atomically
+            if (store.replace(key, existing, newEntry)) {
+                return null;
+            }
+            // Another thread beat us -- read what they stored
+            Entry updated = store.get(key);
+            return updated != null && !updated.isExpired() ? updated.value() : null;
+        }
+        return existing.value();
+    }
+
+    @Override
+    @ManagedAttribute(description = "The number of entries in the repository")
+    public int size() {
+        evictExpired();
+        return store.size();
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        store.clear();
+    }
+
+    private void evictExpired() {
+        Iterator<Map.Entry<String, Entry>> it = store.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<String, Entry> mapEntry = it.next();
+            if (mapEntry.getValue().isExpired()) {
+                it.remove();
+            }
+        }
+    }
+
+    /**
+     * An entry in the repository holding the value and its expiration timestamp.
+     */
+    static final class Entry implements Serializable {
+
+        @Serial
+        private static final long serialVersionUID = 1L;
+
+        private final Object value;
+        private final long expiresAt;
+
+        Entry(Object value, long expiresAt) {
+            this.value = value;
+            this.expiresAt = expiresAt;
+        }
+
+        Object value() {
+            return value;
+        }
+
+        boolean isExpired() {
+            return System.currentTimeMillis() >= expiresAt;
+        }
+    }
+}
diff --git a/core/camel-support/src/test/java/org/apache/camel/support/KeyValueIdempotentRepositoryTest.java b/core/camel-support/src/test/java/org/apache/camel/support/KeyValueIdempotentRepositoryTest.java
new file mode 100644
index 000000000000..6148fb5444ac
--- /dev/null
+++ b/core/camel-support/src/test/java/org/apache/camel/support/KeyValueIdempotentRepositoryTest.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.support;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class KeyValueIdempotentRepositoryTest {
+
+    private MemoryKeyValueRepository kvRepository;
+    private KeyValueIdempotentRepository idempotentRepository;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        kvRepository = new MemoryKeyValueRepository();
+        kvRepository.start();
+        idempotentRepository = new KeyValueIdempotentRepository(kvRepository);
+        idempotentRepository.start();
+    }
+
+    @AfterEach
+    void tearDown() throws Exception {
+        idempotentRepository.stop();
+    }
+
+    @Test
+    void testAddNewKey() {
+        assertThat(idempotentRepository.add("msg-001")).isTrue();
+    }
+
+    @Test
+    void testAddDuplicateKey() {
+        idempotentRepository.add("msg-001");
+
+        assertThat(idempotentRepository.add("msg-001")).isFalse();
+    }
+
+    @Test
+    void testContains() {
+        assertThat(idempotentRepository.contains("msg-001")).isFalse();
+
+        idempotentRepository.add("msg-001");
+
+        assertThat(idempotentRepository.contains("msg-001")).isTrue();
+    }
+
+    @Test
+    void testRemove() {
+        idempotentRepository.add("msg-001");
+
+        assertThat(idempotentRepository.remove("msg-001")).isTrue();
+        assertThat(idempotentRepository.contains("msg-001")).isFalse();
+    }
+
+    @Test
+    void testRemoveNonExistentKey() {
+        assertThat(idempotentRepository.remove("msg-001")).isFalse();
+    }
+
+    @Test
+    void testConfirmIsNoop() {
+        idempotentRepository.add("msg-001");
+
+        assertThat(idempotentRepository.confirm("msg-001")).isTrue();
+        // Key should still be present after confirm
+        assertThat(idempotentRepository.contains("msg-001")).isTrue();
+    }
+
+    @Test
+    void testClear() {
+        idempotentRepository.add("msg-001");
+        idempotentRepository.add("msg-002");
+        idempotentRepository.add("msg-003");
+
+        idempotentRepository.clear();
+
+        assertThat(idempotentRepository.contains("msg-001")).isFalse();
+        assertThat(idempotentRepository.contains("msg-002")).isFalse();
+        assertThat(idempotentRepository.contains("msg-003")).isFalse();
+    }
+
+    @Test
+    void testAddAfterRemoveSucceeds() {
+        idempotentRepository.add("msg-001");
+        idempotentRepository.remove("msg-001");
+
+        // Should be able to add the key again
+        assertThat(idempotentRepository.add("msg-001")).isTrue();
+    }
+
+    @Test
+    void testMultipleKeys() {
+        assertThat(idempotentRepository.add("msg-001")).isTrue();
+        assertThat(idempotentRepository.add("msg-002")).isTrue();
+        assertThat(idempotentRepository.add("msg-003")).isTrue();
+
+        assertThat(idempotentRepository.contains("msg-001")).isTrue();
+        assertThat(idempotentRepository.contains("msg-002")).isTrue();
+        assertThat(idempotentRepository.contains("msg-003")).isTrue();
+
+        // Adding duplicates should fail
+        assertThat(idempotentRepository.add("msg-001")).isFalse();
+        assertThat(idempotentRepository.add("msg-002")).isFalse();
+    }
+
+    @Test
+    void testStoresMarkerValueInUnderlyingRepository() {
+        idempotentRepository.add("msg-001");
+
+        // The underlying KV repository should have the prefixed key with Boolean.TRUE as value
+        assertThat(kvRepository.get("idempotent:msg-001")).isEqualTo(Boolean.TRUE);
+    }
+
+    @Test
+    void testGetRepository() {
+        assertThat(idempotentRepository.getRepository()).isSameAs(kvRepository);
+    }
+
+    @Test
+    void testFactoryMethod() {
+        KeyValueIdempotentRepository created
+                = KeyValueIdempotentRepository.keyValueIdempotentRepository(kvRepository);
+
+        assertThat(created).isNotNull();
+        assertThat(created.getRepository()).isSameAs(kvRepository);
+    }
+
+    @Test
+    void testClearDoesNotAffectOtherPrefixes() {
+        // Simulate another adapter storing entries under a different prefix
+        kvRepository.put("aggregate:order-1", "exchange-holder", 0);
+
+        // Add idempotent entries and clear them
+        idempotentRepository.add("msg-001");
+        idempotentRepository.add("msg-002");
+        idempotentRepository.clear();
+
+        // Idempotent entries should be gone
+        assertThat(idempotentRepository.contains("msg-001")).isFalse();
+        assertThat(idempotentRepository.contains("msg-002")).isFalse();
+
+        // But the aggregate entry should still be there
+        assertThat(kvRepository.get("aggregate:order-1")).isEqualTo("exchange-holder");
+    }
+
+    @Test
+    void testKeyIsolationFromOtherAdapters() {
+        // Store an idempotent entry with key "order-1"
+        idempotentRepository.add("order-1");
+
+        // A different adapter storing under its own prefix should not collide
+        kvRepository.put("aggregate:order-1", "exchange-data", 0);
+
+        // The idempotent entry should still resolve correctly
+        assertThat(idempotentRepository.contains("order-1")).isTrue();
+
+        // And the underlying store has both entries under distinct prefixed keys
+        assertThat(kvRepository.get("idempotent:order-1")).isEqualTo(Boolean.TRUE);
+        assertThat(kvRepository.get("aggregate:order-1")).isEqualTo("exchange-data");
+    }
+}
diff --git a/core/camel-support/src/test/java/org/apache/camel/support/MemoryKeyValueRepositoryTest.java b/core/camel-support/src/test/java/org/apache/camel/support/MemoryKeyValueRepositoryTest.java
new file mode 100644
index 000000000000..f8f9465cb255
--- /dev/null
+++ b/core/camel-support/src/test/java/org/apache/camel/support/MemoryKeyValueRepositoryTest.java
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.camel.support;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+
+class MemoryKeyValueRepositoryTest {
+
+    private MemoryKeyValueRepository repository;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        repository = new MemoryKeyValueRepository();
+        repository.start();
+    }
+
+    @AfterEach
+    void tearDown() throws Exception {
+        repository.stop();
+    }
+
+    @Test
+    void testPutAndGet() {
+        repository.put("key1", "value1", 0);
+
+        assertThat(repository.get("key1")).isEqualTo("value1");
+    }
+
+    @Test
+    void testGetMissingKeyReturnsNull() {
+        assertThat(repository.get("nonexistent")).isNull();
+    }
+
+    @Test
+    void testPutOverwritesExistingValue() {
+        repository.put("key1", "value1", 0);
+        repository.put("key1", "value2", 0);
+
+        assertThat(repository.get("key1")).isEqualTo("value2");
+    }
+
+    @Test
+    void testDelete() {
+        repository.put("key1", "value1", 0);
+
+        Object deleted = repository.delete("key1");
+
+        assertThat(deleted).isEqualTo("value1");
+        assertThat(repository.get("key1")).isNull();
+    }
+
+    @Test
+    void testDeleteMissingKeyReturnsNull() {
+        assertThat(repository.delete("nonexistent")).isNull();
+    }
+
+    @Test
+    void testContains() {
+        repository.put("key1", "value1", 0);
+
+        assertThat(repository.contains("key1")).isTrue();
+        assertThat(repository.contains("nonexistent")).isFalse();
+    }
+
+    @Test
+    void testKeys() {
+        repository.put("key1", "value1", 0);
+        repository.put("key2", "value2", 0);
+        repository.put("key3", "value3", 0);
+
+        Set<String> keys = repository.keys();
+
+        assertThat(keys).containsExactlyInAnyOrder("key1", "key2", "key3");
+    }
+
+    @Test
+    void testKeysEmpty() {
+        assertThat(repository.keys()).isEmpty();
+    }
+
+    @Test
+    void testClear() {
+        repository.put("key1", "value1", 0);
+        repository.put("key2", "value2", 0);
+
+        repository.clear();
+
+        assertThat(repository.size()).isZero();
+        assertThat(repository.get("key1")).isNull();
+        assertThat(repository.get("key2")).isNull();
+    }
+
+    @Test
+    void testSize() {
+        assertThat(repository.size()).isZero();
+
+        repository.put("key1", "value1", 0);
+        assertThat(repository.size()).isEqualTo(1);
+
+        repository.put("key2", "value2", 0);
+        assertThat(repository.size()).isEqualTo(2);
+
+        repository.delete("key1");
+        assertThat(repository.size()).isEqualTo(1);
+    }
+
+    @Test
+    void testPutIfAbsentNewKey() {
+        Object result = repository.putIfAbsent("key1", "value1", 0);
+
+        assertThat(result).isNull();
+        assertThat(repository.get("key1")).isEqualTo("value1");
+    }
+
+    @Test
+    void testPutIfAbsentExistingKey() {
+        repository.put("key1", "value1", 0);
+
+        Object result = repository.putIfAbsent("key1", "value2", 0);
+
+        assertThat(result).isEqualTo("value1");
+        assertThat(repository.get("key1")).isEqualTo("value1");
+    }
+
+    @Test
+    void testTtlExpiration() {
+        // Use a very short TTL
+        repository.put("key1", "value1", 50);
+
+        assertThat(repository.get("key1")).isEqualTo("value1");
+        assertThat(repository.contains("key1")).isTrue();
+
+        // Wait for the entry to expire
+        await().atMost(500, TimeUnit.MILLISECONDS)
+                .untilAsserted(() -> {
+                    assertThat(repository.get("key1")).isNull();
+                    assertThat(repository.contains("key1")).isFalse();
+                });
+    }
+
+    @Test
+    void testTtlExpirationOnKeys() {
+        repository.put("key1", "value1", 50);
+        repository.put("key2", "value2", 0); // no expiration
+
+        await().atMost(500, TimeUnit.MILLISECONDS)
+                .untilAsserted(() -> {
+                    assertThat(repository.keys()).containsExactly("key2");
+                    assertThat(repository.size()).isEqualTo(1);
+                });
+    }
+
+    @Test
+    void testTtlExpirationOnDelete() {
+        repository.put("key1", "value1", 50);
+
+        await().atMost(500, TimeUnit.MILLISECONDS)
+                .untilAsserted(() -> {
+                    // Deleting an expired entry should return null
+                    assertThat(repository.delete("key1")).isNull();
+                });
+    }
+
+    @Test
+    void testPutIfAbsentWithExpiredEntry() {
+        repository.put("key1", "value1", 50);
+
+        await().atMost(500, TimeUnit.MILLISECONDS)
+                .untilAsserted(() -> {
+                    // The entry has expired, so putIfAbsent should succeed
+                    Object result = repository.putIfAbsent("key1", "value2", 0);
+                    assertThat(result).isNull();
+                    assertThat(repository.get("key1")).isEqualTo("value2");
+                });
+    }
+
+    @Test
+    void testNoTtlWithZero() {
+        repository.put("key1", "value1", 0);
+
+        // Entry with TTL=0 should not expire
+        assertThat(repository.get("key1")).isEqualTo("value1");
+        assertThat(repository.contains("key1")).isTrue();
+    }
+
+    @Test
+    void testNoTtlWithNegative() {
+        repository.put("key1", "value1", -1);
+
+        // Entry with negative TTL should not expire
+        assertThat(repository.get("key1")).isEqualTo("value1");
+        assertThat(repository.contains("key1")).isTrue();
+    }
+
+    @Test
+    void testStoresDifferentValueTypes() {
+        repository.put("string", "hello", 0);
+        repository.put("integer", 42, 0);
+        repository.put("boolean", Boolean.TRUE, 0);
+
+        assertThat(repository.get("string")).isEqualTo("hello");
+        assertThat(repository.get("integer")).isEqualTo(42);
+        assertThat(repository.get("boolean")).isEqualTo(Boolean.TRUE);
+    }
+}
diff --git a/docs/components/modules/others/examples/json/state-store-caffeine.json b/docs/components/modules/others/examples/json/state-store-caffeine.json
deleted file mode 120000
index 15277f9fe668..000000000000
--- a/docs/components/modules/others/examples/json/state-store-caffeine.json
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../components/camel-state-store/camel-state-store-caffeine/src/generated/resources/state-store-caffeine.json
\ No newline at end of file
diff --git a/docs/components/modules/others/examples/json/state-store-infinispan.json b/docs/components/modules/others/examples/json/state-store-infinispan.json
deleted file mode 120000
index 9e22e40328f2..000000000000
--- a/docs/components/modules/others/examples/json/state-store-infinispan.json
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../components/camel-state-store/camel-state-store-infinispan/src/generated/resources/state-store-infinispan.json
\ No newline at end of file
diff --git a/docs/components/modules/others/examples/json/state-store-redis.json b/docs/components/modules/others/examples/json/state-store-redis.json
deleted file mode 120000
index aac04d819206..000000000000
--- a/docs/components/modules/others/examples/json/state-store-redis.json
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../components/camel-state-store/camel-state-store-redis/src/generated/resources/state-store-redis.json
\ No newline at end of file
diff --git a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/ComponentsBuilderFactory.java b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/ComponentsBuilderFactory.java
index 8b309c3d2a11..11a2db40080a 100644
--- a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/ComponentsBuilderFactory.java
+++ b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/ComponentsBuilderFactory.java
@@ -4820,7 +4820,8 @@ public interface ComponentsBuilderFactory {
     }
     /**
      * State Store (camel-state-store)
-     * Perform key-value operations against a pluggable state store backend.
+     * Perform key-value operations against a pluggable KeyValueRepository
+     * backend.
      * 
      * Category: cache
      * Since: 4.23
diff --git a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/StateStoreComponentBuilderFactory.java b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/StateStoreComponentBuilderFactory.java
index c7f95c5694d0..cb2444613756 100644
--- a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/StateStoreComponentBuilderFactory.java
+++ b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/StateStoreComponentBuilderFactory.java
@@ -24,7 +24,7 @@ import org.apache.camel.builder.component.ComponentBuilder;
 import org.apache.camel.component.statestore.StateStoreComponent;
 
 /**
- * Perform key-value operations against a pluggable state store backend.
+ * Perform key-value operations against a pluggable KeyValueRepository backend.
  * 
  * Generated by camel build tools - do NOT edit this file!
  */
@@ -33,7 +33,8 @@ public interface StateStoreComponentBuilderFactory {
 
     /**
      * State Store (camel-state-store)
-     * Perform key-value operations against a pluggable state store backend.
+     * Perform key-value operations against a pluggable KeyValueRepository
+     * backend.
      * 
      * Category: cache
      * Since: 4.23
diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointHeaderBuilders.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointHeaderBuilders.java
index 6a742870d0d2..55ee8629deff 100644
--- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointHeaderBuilders.java
+++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointHeaderBuilders.java
@@ -3696,7 +3696,8 @@ public class EndpointHeaderBuilders {
     }
     /**
      * State Store (camel-state-store)
-     * Perform key-value operations against a pluggable state store backend.
+     * Perform key-value operations against a pluggable KeyValueRepository
+     * backend.
      * 
      * Category: cache
      * Since: 4.23
diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
index 74ec4d16bca6..13705f86aa04 100644
--- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
+++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
@@ -16109,7 +16109,8 @@ public class StaticEndpointBuilders {
     }
     /**
      * State Store (camel-state-store)
-     * Perform key-value operations against a pluggable state store backend.
+     * Perform key-value operations against a pluggable KeyValueRepository
+     * backend.
      * 
      * Category: cache
      * Since: 4.23
@@ -16128,7 +16129,8 @@ public class StaticEndpointBuilders {
     }
     /**
      * State Store (camel-state-store)
-     * Perform key-value operations against a pluggable state store backend.
+     * Perform key-value operations against a pluggable KeyValueRepository
+     * backend.
      * 
      * Category: cache
      * Since: 4.23
diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/StateStoreEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/StateStoreEndpointBuilderFactory.java
index 3e9d10aaf56a..884023f13c62 100644
--- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/StateStoreEndpointBuilderFactory.java
+++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/StateStoreEndpointBuilderFactory.java
@@ -27,7 +27,7 @@ import org.apache.camel.builder.EndpointProducerBuilder;
 import org.apache.camel.builder.endpoint.AbstractEndpointBuilder;
 
 /**
- * Perform key-value operations against a pluggable state store backend.
+ * Perform key-value operations against a pluggable KeyValueRepository backend.
  * 
  * Generated by camel build tools - do NOT edit this file!
  */
@@ -164,11 +164,10 @@ public interface StateStoreEndpointBuilderFactory {
         }
         /**
          * The backend to use. If not set, auto-discovers a single
-         * StateStoreBackend from the registry, or falls back to an in-memory
+         * KeyValueRepository from the registry, or falls back to an in-memory
          * store.
          * 
-         * The option is a:
-         * <code>org.apache.camel.component.statestore.StateStoreBackend</code>
+         * The option is a: <code>org.apache.camel.spi.KeyValueRepository</code>
          * type.
          * 
          * Group: advanced
@@ -176,18 +175,17 @@ public interface StateStoreEndpointBuilderFactory {
          * @param backend the value to set
          * @return the dsl builder
          */
-        default AdvancedStateStoreEndpointBuilder backend(org.apache.camel.component.statestore.StateStoreBackend backend) {
+        default AdvancedStateStoreEndpointBuilder backend(org.apache.camel.spi.KeyValueRepository backend) {
             doSetProperty("backend", backend);
             return this;
         }
         /**
          * The backend to use. If not set, auto-discovers a single
-         * StateStoreBackend from the registry, or falls back to an in-memory
+         * KeyValueRepository from the registry, or falls back to an in-memory
          * store.
          * 
          * The option will be converted to a
-         * <code>org.apache.camel.component.statestore.StateStoreBackend</code>
-         * type.
+         * <code>org.apache.camel.spi.KeyValueRepository</code> type.
          * 
          * Group: advanced
          * 
@@ -203,7 +201,8 @@ public interface StateStoreEndpointBuilderFactory {
     public interface StateStoreBuilders {
         /**
          * State Store (camel-state-store)
-         * Perform key-value operations against a pluggable state store backend.
+         * Perform key-value operations against a pluggable KeyValueRepository
+         * backend.
          * 
          * Category: cache
          * Since: 4.23
@@ -216,7 +215,8 @@ public interface StateStoreEndpointBuilderFactory {
         }
         /**
          * State Store (camel-state-store)
-         * Perform key-value operations against a pluggable state store backend.
+         * Perform key-value operations against a pluggable KeyValueRepository
+         * backend.
          * 
          * Category: cache
          * Since: 4.23
@@ -235,7 +235,8 @@ public interface StateStoreEndpointBuilderFactory {
         }
         /**
          * State Store (camel-state-store)
-         * Perform key-value operations against a pluggable state store backend.
+         * Perform key-value operations against a pluggable KeyValueRepository
+         * backend.
          * 
          * Category: cache
          * Since: 4.23
diff --git a/parent/pom.xml b/parent/pom.xml
index e14c7018b785..818610c8b294 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -2810,21 +2810,6 @@
                 <artifactId>camel-state-store</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.apache.camel</groupId>
-                <artifactId>camel-state-store-caffeine</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.camel</groupId>
-                <artifactId>camel-state-store-infinispan</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.camel</groupId>
-                <artifactId>camel-state-store-redis</artifactId>
-                <version>${project.version}</version>
-            </dependency>
             <dependency>
                 <groupId>org.apache.camel</groupId>
                 <artifactId>camel-stax</artifactId>