diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringQueryMapEncoder.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringQueryMapEncoder.java
index 6ec743b44..be6a3b24c 100644
--- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringQueryMapEncoder.java
+++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/PageableSpringQueryMapEncoder.java
@@ -21,8 +21,6 @@
import java.util.List;
import java.util.Map;
-import feign.querymap.BeanQueryMapEncoder;
-
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@@ -35,7 +33,7 @@
* @author Gokalp Kuscu
* @since 2.2.8
*/
-public class PageableSpringQueryMapEncoder extends BeanQueryMapEncoder {
+public class PageableSpringQueryMapEncoder extends RecordQueryMapEncoder {
/**
* Page index parameter name.
diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/RecordQueryMapEncoder.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/RecordQueryMapEncoder.java
new file mode 100644
index 000000000..84c055ae9
--- /dev/null
+++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/RecordQueryMapEncoder.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2013-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://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.springframework.cloud.openfeign.support;
+
+import java.util.Collections;
+import java.util.Map;
+
+import feign.QueryMapEncoder;
+import feign.querymap.BeanQueryMapEncoder;
+import feign.querymap.FieldQueryMapEncoder;
+
+/**
+ * A {@link QueryMapEncoder} that supports Java Record types.
+ *
+ * This encoder detects Record types using {@link Class#isRecord()} and delegates to
+ * {@link FieldQueryMapEncoder} for field-based encoding. For non-Record types (standard
+ * JavaBeans/POJOs), it falls back to {@link BeanQueryMapEncoder}.
+ *
+ *
+ * This class is designed to be extended by encoders that need additional type handling,
+ * such as {@link PageableSpringQueryMapEncoder}.
+ *
+ *
+ * @author Joo
+ * @since 4.2.0
+ * @see FieldQueryMapEncoder
+ * @see BeanQueryMapEncoder
+ * @see PageableSpringQueryMapEncoder
+ */
+public class RecordQueryMapEncoder implements QueryMapEncoder {
+
+ private final QueryMapEncoder recordDelegate;
+
+ private final QueryMapEncoder beanDelegate;
+
+ /**
+ * Creates a new instance with default encoders.
+ *
+ * Uses {@link FieldQueryMapEncoder} for Records and {@link BeanQueryMapEncoder} for
+ * POJOs.
+ *
+ */
+ public RecordQueryMapEncoder() {
+ this(new FieldQueryMapEncoder(), new BeanQueryMapEncoder());
+ }
+
+ /**
+ * Creates a new instance with custom encoders.
+ *
+ * This constructor is primarily intended for testing and advanced use cases where
+ * custom encoding behavior is required.
+ *
+ * @param recordDelegate encoder for Record types
+ * @param beanDelegate encoder for non-Record types (POJOs)
+ */
+ public RecordQueryMapEncoder(QueryMapEncoder recordDelegate, QueryMapEncoder beanDelegate) {
+ this.recordDelegate = recordDelegate;
+ this.beanDelegate = beanDelegate;
+ }
+
+ @Override
+ public Map encode(Object object) {
+ if (object == null) {
+ return Collections.emptyMap();
+ }
+
+ if (object.getClass().isRecord()) {
+ return this.recordDelegate.encode(object);
+ }
+
+ return this.beanDelegate.encode(object);
+ }
+
+}
diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/RecordQueryMapEncoderTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/RecordQueryMapEncoderTests.java
new file mode 100644
index 000000000..2f3ddd40b
--- /dev/null
+++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/RecordQueryMapEncoderTests.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2013-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://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.springframework.cloud.openfeign.support;
+
+import java.util.Collections;
+import java.util.Map;
+
+import feign.QueryMapEncoder;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link RecordQueryMapEncoder}.
+ *
+ * @author Joo
+ */
+class RecordQueryMapEncoderTests {
+
+ private final RecordQueryMapEncoder encoder = new RecordQueryMapEncoder();
+
+ @Test
+ void shouldEncodeSimpleRecord() {
+ // given
+ SimpleRecord record = new SimpleRecord("hello", 1);
+
+ // when
+ Map result = this.encoder.encode(record);
+
+ // then
+ assertThat(result).isNotNull();
+ assertThat(result).hasSize(2);
+ assertThat(result.get("keyword")).isEqualTo("hello");
+ assertThat(result.get("page")).isEqualTo(1);
+ }
+
+ @Test
+ void shouldEncodeEmptyRecord() {
+ // given
+ EmptyRecord record = new EmptyRecord();
+
+ // when
+ Map result = this.encoder.encode(record);
+
+ // then
+ assertThat(result).isNotNull();
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ void shouldReturnEmptyMapForNullInput() {
+ // when
+ Map result = this.encoder.encode(null);
+
+ // then
+ assertThat(result).isNotNull();
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ void shouldDelegateToBeanEncoderForPojo() {
+ // given
+ SimplePojo pojo = new SimplePojo();
+ pojo.setName("test");
+
+ // when
+ Map result = this.encoder.encode(pojo);
+
+ // then
+ assertThat(result).isNotNull();
+ assertThat(result).containsEntry("name", "test");
+ }
+
+ @Test
+ void shouldUseProvidedDelegates() {
+ // given
+ QueryMapEncoder mockRecordEncoder = mock(QueryMapEncoder.class);
+ QueryMapEncoder mockBeanEncoder = mock(QueryMapEncoder.class);
+ RecordQueryMapEncoder customEncoder = new RecordQueryMapEncoder(mockRecordEncoder, mockBeanEncoder);
+
+ SimpleRecord record = new SimpleRecord("test", 1);
+ when(mockRecordEncoder.encode(record)).thenReturn(Collections.emptyMap());
+
+ // when
+ customEncoder.encode(record);
+
+ // then
+ verify(mockRecordEncoder).encode(record);
+ }
+
+ @Test
+ void shouldUseProvidedBeanDelegate() {
+ // given
+ QueryMapEncoder mockRecordEncoder = mock(QueryMapEncoder.class);
+ QueryMapEncoder mockBeanEncoder = mock(QueryMapEncoder.class);
+ RecordQueryMapEncoder customEncoder = new RecordQueryMapEncoder(mockRecordEncoder, mockBeanEncoder);
+
+ SimplePojo pojo = new SimplePojo();
+ when(mockBeanEncoder.encode(pojo)).thenReturn(Collections.emptyMap());
+
+ // when
+ customEncoder.encode(pojo);
+
+ // then
+ verify(mockBeanEncoder).encode(pojo);
+ }
+
+ // Test Records (local definitions)
+ record SimpleRecord(String keyword, int page) {
+ }
+
+ record EmptyRecord() {
+ }
+
+ record RecordWithNullField(String value) {
+ }
+
+ // Test POJO for fallback testing
+ public static class SimplePojo {
+
+ private String name;
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ }
+
+}