diff --git a/coil-core/src/commonMain/kotlin/coil3/ComponentRegistry.kt b/coil-core/src/commonMain/kotlin/coil3/ComponentRegistry.kt
index 71a4f7b827..da42071c72 100644
--- a/coil-core/src/commonMain/kotlin/coil3/ComponentRegistry.kt
+++ b/coil-core/src/commonMain/kotlin/coil3/ComponentRegistry.kt
@@ -118,7 +118,6 @@ class ComponentRegistry private constructor(
     fun newBuilder() = Builder(this)
 
     class Builder {
-
         internal val interceptors: MutableList<Interceptor>
         internal val mappers: MutableList<Pair<Mapper<out Any, *>, KClass<out Any>>>
         internal val keyers: MutableList<Pair<Keyer<out Any>, KClass<out Any>>>
diff --git a/coil-core/src/commonMain/kotlin/coil3/memory/MemoryCacheService.kt b/coil-core/src/commonMain/kotlin/coil3/memory/MemoryCacheService.kt
index 6276284411..153260e9ad 100644
--- a/coil-core/src/commonMain/kotlin/coil3/memory/MemoryCacheService.kt
+++ b/coil-core/src/commonMain/kotlin/coil3/memory/MemoryCacheService.kt
@@ -20,6 +20,7 @@ import coil3.size.isOriginal
 import coil3.size.pxOrElse
 import coil3.util.Logger
 import coil3.util.isPlaceholderCached
+import coil3.util.key
 import coil3.util.log
 import kotlin.math.abs
 
@@ -43,7 +44,7 @@ internal class MemoryCacheService(
 
         // Slow path: create a new memory cache key.
         eventListener.keyStart(request, mappedData)
-        val key = imageLoader.components.key(mappedData, options)
+        val key = imageLoader.components.key(mappedData, options, logger, TAG)
         eventListener.keyEnd(request, key)
         if (key == null) {
             return null
diff --git a/coil-core/src/commonMain/kotlin/coil3/util/utils.kt b/coil-core/src/commonMain/kotlin/coil3/util/utils.kt
index 8dd4a6f783..36360da560 100644
--- a/coil-core/src/commonMain/kotlin/coil3/util/utils.kt
+++ b/coil-core/src/commonMain/kotlin/coil3/util/utils.kt
@@ -9,9 +9,11 @@ import coil3.decode.Decoder
 import coil3.fetch.Fetcher
 import coil3.intercept.Interceptor
 import coil3.intercept.RealInterceptorChain
+import coil3.key.Keyer
 import coil3.request.ErrorResult
 import coil3.request.ImageRequest
 import coil3.request.NullRequestDataException
+import coil3.request.Options
 import kotlin.coroutines.CoroutineContext
 import kotlin.experimental.ExperimentalNativeApi
 import kotlin.reflect.KClass
@@ -46,6 +48,31 @@ internal fun AutoCloseable.closeQuietly() {
 
 internal val EMPTY_IMAGE_FACTORY: (ImageRequest) -> Image? = { null }
 
+/** Same as [ComponentRegistry.key], but with extra logging. */
+@Suppress("UNCHECKED_CAST")
+internal fun ComponentRegistry.key(
+    data: Any,
+    options: Options,
+    logger: Logger?,
+    tag: String,
+): String? {
+    var hasKeyerForType = false
+    keyers.forEachIndices { (keyer, type) ->
+        if (type.isInstance(data)) {
+            hasKeyerForType = true
+            (keyer as Keyer<Any>).key(data, options)?.let { return it }
+        }
+    }
+    if (!hasKeyerForType) {
+        logger?.log(tag, Logger.Level.Warn) {
+            "No keyer is registered for data with type '${data::class.simpleName}'. " +
+                "Register Keyer<${data::class.simpleName}> in the component registry to " +
+                "cache the output image in the memory cache."
+        }
+    }
+    return null
+}
+
 internal fun ComponentRegistry.Builder.addFirst(
     pair: Pair<Fetcher.Factory<*>, KClass<*>>?
 ) = apply { if (pair != null) lazyFetcherFactories.add(0) { listOf(pair) } }