diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java b/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java
index f12d2119ad..9364e800f2 100644
--- a/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java
+++ b/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java
@@ -69,7 +69,9 @@ public @interface CacheEvict {
* following meta-data:
*
* - {@code #result} for a reference to the result of the method invocation, which
- * can only be used if {@link #beforeInvocation()} is {@code false}.
+ * can only be used if {@link #beforeInvocation()} is {@code false}. For supported
+ * wrappers such as {@code Optional}, {@code #result} refers to the actual object,
+ * not the wrapper
* - {@code #root.method}, {@code #root.target}, and {@code #root.caches} for
* references to the {@link java.lang.reflect.Method method}, target object, and
* affected cache(s) respectively.
diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java b/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java
index cd48e41090..72d41be082 100644
--- a/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java
+++ b/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java
@@ -31,7 +31,9 @@ import org.springframework.core.annotation.AliasFor;
*
* In contrast to the {@link Cacheable @Cacheable} annotation, this annotation
* does not cause the advised method to be skipped. Rather, it always causes the
- * method to be invoked and its result to be stored in the associated cache.
+ * method to be invoked and its result to be stored in the associated cache. Note
+ * that Java8's {@code Optional} return types are automatically handled and its
+ * content is stored in the cache if present.
*
*
This annotation may be used as a meta-annotation to create custom
* composed annotations with attribute overrides.
@@ -73,7 +75,9 @@ public @interface CachePut {
*
The SpEL expression evaluates against a dedicated context that provides the
* following meta-data:
*
- * - {@code #result} for a reference to the result of the method invocation.
+ * - {@code #result} for a reference to the result of the method invocation. For
+ * supported wrappers such as {@code Optional}, {@code #result} refers to the actual
+ * object, not the wrapper
* - {@code #root.method}, {@code #root.target}, and {@code #root.caches} for
* references to the {@link java.lang.reflect.Method method}, target object, and
* affected cache(s) respectively.
@@ -138,7 +142,9 @@ public @interface CachePut {
* The SpEL expression evaluates against a dedicated context that provides the
* following meta-data:
*
- * - {@code #result} for a reference to the result of the method invocation.
+ * - {@code #result} for a reference to the result of the method invocation. For
+ * supported wrappers such as {@code Optional}, {@code #result} refers to the actual
+ * object, not the wrapper
* - {@code #root.method}, {@code #root.target}, and {@code #root.caches} for
* references to the {@link java.lang.reflect.Method method}, target object, and
* affected cache(s) respectively.
diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java b/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java
index 225ada51eb..9defd9553b 100644
--- a/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java
+++ b/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java
@@ -38,7 +38,9 @@ import org.springframework.core.annotation.AliasFor;
* replace the default one (see {@link #keyGenerator}).
*
* If no value is found in the cache for the computed key, the target method
- * will be invoked and the returned value stored in the associated cache.
+ * will be invoked and the returned value stored in the associated cache. Note
+ * that Java8's {@code Optional} return types are automatically handled and its
+ * content is stored in the cache if present.
*
*
This annotation may be used as a meta-annotation to create custom
* composed annotations with attribute overrides.
@@ -144,7 +146,9 @@ public @interface Cacheable {
*
The SpEL expression evaluates against a dedicated context that provides the
* following meta-data:
*
- * - {@code #result} for a reference to the result of the method invocation.
+ * - {@code #result} for a reference to the result of the method invocation. For
+ * supported wrappers such as {@code Optional}, {@code #result} refers to the actual
+ * object, not the wrapper
* - {@code #root.method}, {@code #root.target}, and {@code #root.caches} for
* references to the {@link java.lang.reflect.Method method}, target object, and
* affected cache(s) respectively.
diff --git a/src/asciidoc/integration.adoc b/src/asciidoc/integration.adoc
index 29775b59be..b6e17173a6 100644
--- a/src/asciidoc/integration.adoc
+++ b/src/asciidoc/integration.adoc
@@ -8333,6 +8333,18 @@ only want to cache paperback books:
public Book findBook(String name)
----
+The cache abstraction supports `java.util.Optional`, using its content as cached value
+only if it present. `#result` always refers to the business entity and never on a
+supported wrapper so the previous example can be rewritten as follows:
+
+[source,java,indent=0]
+[subs="verbatim,quotes"]
+----
+ @Cacheable(cacheNames="book", condition="#name.length < 32", **unless="#result.hardback"**)
+ public Optional findBook(String name)
+----
+
+Note that `result` still refers to `Book` and not `Optional`.
[[cache-spel-context]]
===== Available caching SpEL evaluation context
@@ -8389,7 +8401,8 @@ conditional computations:
| evaluation context
| The result of the method call (the value to be cached). Only available in `unless`
expressions, `cache put` expressions (to compute the `key`), or `cache evict`
- expressions (when `beforeInvocation` is `false`).
+ expressions (when `beforeInvocation` is `false`). For supported wrappers such as
+ `Optional`, `#result` refers to the actual object, not the wrapper.
| `#result`
|===