diff --git a/spring-data-jdbc/pom.xml b/spring-data-jdbc/pom.xml
index 73b1d2f7a0..78fcf41cdb 100644
--- a/spring-data-jdbc/pom.xml
+++ b/spring-data-jdbc/pom.xml
@@ -189,6 +189,13 @@
test
+
+ io.mockk
+ mockk-jvm
+ ${mockk}
+ test
+
+
@@ -239,6 +246,19 @@
${hikari.version}
test
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ true
+
+
+
+ org.jetbrains.kotlin
+ kotlin-reflect
+ true
+
diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateOperationsExtensions.kt b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateOperationsExtensions.kt
new file mode 100644
index 0000000000..4ac6033f4f
--- /dev/null
+++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/core/JdbcAggregateOperationsExtensions.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2017-2024 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.data.jdbc.core
+
+import org.springframework.data.domain.Page
+import org.springframework.data.domain.Pageable
+import org.springframework.data.domain.Sort
+import org.springframework.data.relational.core.query.Query
+
+import java.util.Optional
+
+/**
+ * Extensions for [JdbcAggregateOperations].
+ *
+ * @author Felix Desyatirikov
+ * @since 3.5
+ */
+
+/**
+ * Extension for [JdbcAggregateOperations.count].
+ */
+inline fun JdbcAggregateOperations.count(): Long =
+ count(T::class.java)
+
+/**
+ * Extension for [JdbcAggregateOperations.count] with a query.
+ */
+inline fun JdbcAggregateOperations.count(query: Query): Long =
+ count(query, T::class.java)
+
+/**
+ * Extension for [JdbcAggregateOperations.exists].
+ */
+inline fun JdbcAggregateOperations.exists(query: Query): Boolean =
+ exists(query, T::class.java)
+
+/**
+ * Extension for [JdbcAggregateOperations.existsById].
+ */
+inline fun JdbcAggregateOperations.existsById(id: Any): Boolean =
+ existsById(id, T::class.java)
+
+/**
+ * Extension for [JdbcAggregateOperations.findById].
+ */
+inline fun JdbcAggregateOperations.findById(id: Any): T? =
+ findById(id, T::class.java)
+
+/**
+ * Extension for [JdbcAggregateOperations.findAllById].
+ */
+inline fun JdbcAggregateOperations.findAllById(ids: Iterable<*>): List =
+ findAllById(ids, T::class.java)
+
+/**
+ * Extension for [JdbcAggregateOperations.findAll].
+ */
+inline fun JdbcAggregateOperations.findAll(): List =
+ findAll(T::class.java)
+
+/**
+ * Extension for [JdbcAggregateOperations.findAll] with sorting.
+ */
+inline fun JdbcAggregateOperations.findAll(sort: Sort): List =
+ findAll(T::class.java, sort)
+
+/**
+ * Extension for [JdbcAggregateOperations.findAll] with pagination.
+ */
+inline fun JdbcAggregateOperations.findAll(pageable: Pageable): Page =
+ findAll(T::class.java, pageable)
+
+/**
+ * Extension for [JdbcAggregateOperations.findOne] with a query.
+ */
+inline fun JdbcAggregateOperations.findOne(query: Query): Optional =
+ findOne(query, T::class.java)
+
+/**
+ * Extension for [JdbcAggregateOperations.findAll] with a query.
+ */
+inline fun JdbcAggregateOperations.findAll(query: Query): List =
+ findAll(query, T::class.java)
+
+/**
+ * Extension for [JdbcAggregateOperations.findAll] with query and pagination.
+ */
+inline fun JdbcAggregateOperations.findAll(query: Query, pageable: Pageable): Page =
+ findAll(query, T::class.java, pageable)
+
+/**
+ * Extension for [JdbcAggregateOperations.deleteById].
+ */
+inline fun JdbcAggregateOperations.deleteById(id: Any): Unit =
+ deleteById(id, T::class.java)
+
+/**
+ * Extension for [JdbcAggregateOperations.deleteAllById].
+ */
+inline fun JdbcAggregateOperations.deleteAllById(ids: Iterable<*>): Unit =
+ deleteAllById(ids, T::class.java)
+
+/**
+ * Extension for [JdbcAggregateOperations.deleteAll].
+ */
+inline fun JdbcAggregateOperations.deleteAll(): Unit =
+ deleteAll(T::class.java)
\ No newline at end of file
diff --git a/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateOperationsExtensionsTests.kt b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateOperationsExtensionsTests.kt
new file mode 100644
index 0000000000..5acb2faea2
--- /dev/null
+++ b/spring-data-jdbc/src/test/java/org/springframework/data/jdbc/core/JdbcAggregateOperationsExtensionsTests.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2020-2024 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.data.jdbc.core
+
+import io.mockk.mockk
+import io.mockk.verify
+import org.junit.Test
+import org.springframework.data.domain.Pageable
+import org.springframework.data.domain.Sort
+import org.springframework.data.jdbc.testing.TestClass
+import org.springframework.data.relational.core.query.Query
+
+/**
+ * Unit tests for [JdbcAggregateOperations].
+ *
+ * @author Felix Desyatirikov
+ */
+
+class JdbcAggregateOperationsExtensionsTests {
+
+ val operations = mockk(relaxed = true)
+
+ @Test // gh-1961
+ fun `count with reified type parameter extension should call its Java counterpart`() {
+ operations.count()
+ verify { operations.count(TestClass::class.java) }
+ }
+
+ @Test // gh-1961
+ fun `count(Query) with reified type parameter extension should call its Java counterpart`() {
+ val query = mockk(relaxed = true)
+ operations.count(query)
+ verify {
+ operations.count(query, TestClass::class.java)
+ }
+ }
+
+ @Test // gh-1961
+ fun `exists(Query) with reified type parameter extension should call its Java counterpart`() {
+ val query = mockk(relaxed = true)
+ operations.exists(query)
+ verify {
+ operations.exists(query, TestClass::class.java)
+ }
+ }
+
+ @Test // gh-1961
+ fun `existsById(id) with reified type parameter extension should call its Java counterpart`() {
+ val id = 1L
+ operations.existsById(id)
+ verify {
+ operations.existsById(id, TestClass::class.java)
+ }
+ }
+
+ @Test // gh-1961
+ fun `findById(id) with reified type parameter extension should call its Java counterpart`() {
+ val id = 1L
+ operations.findById(id)
+ verify {
+ operations.findById(id, TestClass::class.java)
+ }
+ }
+
+ @Test // gh-1961
+ fun `findAllById(ids) with reified type parameter extension should call its Java counterpart`() {
+ val ids = listOf(1L, 2L)
+ operations.findAllById(ids)
+ verify {
+ operations.findAllById(ids, TestClass::class.java)
+ }
+ }
+
+ @Test // gh-1961
+ fun `findAll() with reified type parameter extension should call its Java counterpart`() {
+ operations.findAll()
+ verify {
+ operations.findAll(TestClass::class.java)
+ }
+ }
+
+ @Test // gh-1961
+ fun `findAll(Sort) with reified type parameter extension should call its Java counterpart`() {
+ val sort = mockk(relaxed = true)
+ operations.findAll(sort)
+ verify {
+ operations.findAll(TestClass::class.java, sort)
+ }
+ }
+
+ @Test // gh-1961
+ fun `findAll(Pageable) with reified type parameter extension should call its Java counterpart`() {
+ val pageable = mockk(relaxed = true)
+ operations.findAll(pageable)
+ verify {
+ operations.findAll(TestClass::class.java, pageable)
+ }
+ }
+
+ @Test // gh-1961
+ fun `findOne(Query) with reified type parameter extension should call its Java counterpart`() {
+ val query = mockk(relaxed = true)
+ operations.findOne(query)
+ verify {
+ operations.findOne(query, TestClass::class.java)
+ }
+ }
+
+ @Test // gh-1961
+ fun `findAll(Query) with reified type parameter extension should call its Java counterpart`() {
+ val query = mockk(relaxed = true)
+ operations.findAll(query)
+ verify {
+ operations.findAll(query, TestClass::class.java)
+ }
+ }
+
+
+ @Test // gh-1961
+ fun `findAll(Query, Pageable) with reified type parameter extension should call its Java counterpart`() {
+ val query = mockk(relaxed = true)
+ val pageable = mockk(relaxed = true)
+ operations.findAll(query, pageable)
+ verify {
+ operations.findAll(query, TestClass::class.java, pageable)
+ }
+ }
+
+ @Test // gh-1961
+ fun `deleteById(id) with reified type parameter extension should call its Java counterpart`() {
+ val id = 1L
+ operations.deleteById(id)
+ verify {
+ operations.deleteById(id, TestClass::class.java)
+ }
+ }
+
+ @Test // gh-1961
+ fun `deleteAllById(ids) with reified type parameter extension should call its Java counterpart`() {
+ val ids = listOf(1L, 2L)
+ operations.deleteAllById(ids)
+ verify {
+ operations.deleteAllById(ids, TestClass::class.java)
+ }
+ }
+
+ @Test // gh-1961
+ fun `deleteAll(ids) with reified type parameter extension should call its Java counterpart`() {
+ operations.deleteAll()
+ verify {
+ operations.deleteAll(TestClass::class.java)
+ }
+ }
+}
\ No newline at end of file