diff --git a/src/Caching/Hybrid/src/Internal/DefaultHybridCache.L2.cs b/src/Caching/Hybrid/src/Internal/DefaultHybridCache.L2.cs
index 578528e9d4be..e0480abff5b8 100644
--- a/src/Caching/Hybrid/src/Internal/DefaultHybridCache.L2.cs
+++ b/src/Caching/Hybrid/src/Internal/DefaultHybridCache.L2.cs
@@ -106,9 +106,19 @@ private DistributedCacheEntryOptions GetOptions(HybridCacheEntryOptions? options
         DistributedCacheEntryOptions? result = null;
         if (options is not null && options.Expiration.HasValue && options.Expiration.GetValueOrDefault() != _defaultExpiration)
         {
-            result = options.ToDistributedCacheEntryOptions();
+            result = ToDistributedCacheEntryOptions(options);
         }
         return result ?? _defaultDistributedCacheExpiration;
+
+#if NET8_0_OR_GREATER
+        // internal method memoizes this allocation; since it is "init", it is immutable (outside reflection)
+        [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(ToDistributedCacheEntryOptions))]
+        extern static DistributedCacheEntryOptions? ToDistributedCacheEntryOptions(HybridCacheEntryOptions options);
+#else
+        // withoug that helper method, we'll just eat the alloc (down-level TFMs)
+        static DistributedCacheEntryOptions ToDistributedCacheEntryOptions(HybridCacheEntryOptions options)
+            => new() { AbsoluteExpirationRelativeToNow = options.Expiration };
+#endif
     }
 
     internal void SetL1<T>(string key, CacheItem<T> value, HybridCacheEntryOptions? options)
diff --git a/src/Caching/Hybrid/src/Internal/DefaultHybridCache.cs b/src/Caching/Hybrid/src/Internal/DefaultHybridCache.cs
index a41c42ba635b..3dc98e55ef3b 100644
--- a/src/Caching/Hybrid/src/Internal/DefaultHybridCache.cs
+++ b/src/Caching/Hybrid/src/Internal/DefaultHybridCache.cs
@@ -108,12 +108,12 @@ public DefaultHybridCache(IOptions<HybridCacheOptions> options, IServiceProvider
     private HybridCacheEntryFlags GetEffectiveFlags(HybridCacheEntryOptions? options)
         => (options?.Flags | _hardFlags) ?? _defaultFlags;
 
-    public override ValueTask<T> GetOrCreateAsync<TState, T>(string key, TState state, Func<TState, CancellationToken, ValueTask<T>> underlyingDataCallback, HybridCacheEntryOptions? options = null, IReadOnlyCollection<string>? tags = null, CancellationToken token = default)
+    public override ValueTask<T> GetOrCreateAsync<TState, T>(string key, TState state, Func<TState, CancellationToken, ValueTask<T>> underlyingDataCallback, HybridCacheEntryOptions? options = null, IEnumerable<string>? tags = null, CancellationToken cancellationToken = default)
     {
-        var canBeCanceled = token.CanBeCanceled;
+        var canBeCanceled = cancellationToken.CanBeCanceled;
         if (canBeCanceled)
         {
-            token.ThrowIfCancellationRequested();
+            cancellationToken.ThrowIfCancellationRequested();
         }
 
         var flags = GetEffectiveFlags(options);
@@ -141,7 +141,7 @@ public override ValueTask<T> GetOrCreateAsync<TState, T>(string key, TState stat
             }
         }
 
-        return stampede.JoinAsync(token);
+        return stampede.JoinAsync(cancellationToken);
     }
 
     public override ValueTask RemoveAsync(string key, CancellationToken token = default)
@@ -153,7 +153,7 @@ public override ValueTask RemoveAsync(string key, CancellationToken token = defa
     public override ValueTask RemoveByTagAsync(string tag, CancellationToken token = default)
         => default; // tags not yet implemented
 
-    public override ValueTask SetAsync<T>(string key, T value, HybridCacheEntryOptions? options = null, IReadOnlyCollection<string>? tags = null, CancellationToken token = default)
+    public override ValueTask SetAsync<T>(string key, T value, HybridCacheEntryOptions? options = null, IEnumerable<string>? tags = null, CancellationToken token = default)
     {
         // since we're forcing a write: disable L1+L2 read; we'll use a direct pass-thru of the value as the callback, to reuse all the code;
         // note also that stampede token is not shared with anyone else
diff --git a/src/Caching/Hybrid/src/PublicAPI.Unshipped.txt b/src/Caching/Hybrid/src/PublicAPI.Unshipped.txt
index 19682fb4a0f2..abe172bda56a 100644
--- a/src/Caching/Hybrid/src/PublicAPI.Unshipped.txt
+++ b/src/Caching/Hybrid/src/PublicAPI.Unshipped.txt
@@ -1,34 +1,4 @@
 #nullable enable
-abstract Microsoft.Extensions.Caching.Hybrid.HybridCache.GetOrCreateAsync<TState, T>(string! key, TState state, System.Func<TState, System.Threading.CancellationToken, System.Threading.Tasks.ValueTask<T>>! factory, Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions? options = null, System.Collections.Generic.IReadOnlyCollection<string!>? tags = null, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<T>
-abstract Microsoft.Extensions.Caching.Hybrid.HybridCache.RemoveAsync(string! key, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask
-abstract Microsoft.Extensions.Caching.Hybrid.HybridCache.RemoveByTagAsync(string! tag, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask
-abstract Microsoft.Extensions.Caching.Hybrid.HybridCache.SetAsync<T>(string! key, T value, Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions? options = null, System.Collections.Generic.IReadOnlyCollection<string!>? tags = null, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask
-Microsoft.Extensions.Caching.Distributed.IBufferDistributedCache
-Microsoft.Extensions.Caching.Distributed.IBufferDistributedCache.Set(string! key, System.Buffers.ReadOnlySequence<byte> value, Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions! options) -> void
-Microsoft.Extensions.Caching.Distributed.IBufferDistributedCache.SetAsync(string! key, System.Buffers.ReadOnlySequence<byte> value, Microsoft.Extensions.Caching.Distributed.DistributedCacheEntryOptions! options, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask
-Microsoft.Extensions.Caching.Distributed.IBufferDistributedCache.TryGet(string! key, System.Buffers.IBufferWriter<byte>! destination) -> bool
-Microsoft.Extensions.Caching.Distributed.IBufferDistributedCache.TryGetAsync(string! key, System.Buffers.IBufferWriter<byte>! destination, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<bool>
-Microsoft.Extensions.Caching.Hybrid.HybridCache
-Microsoft.Extensions.Caching.Hybrid.HybridCache.GetOrCreateAsync<T>(string! key, System.Func<System.Threading.CancellationToken, System.Threading.Tasks.ValueTask<T>>! factory, Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions? options = null, System.Collections.Generic.IReadOnlyCollection<string!>? tags = null, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask<T>
-Microsoft.Extensions.Caching.Hybrid.HybridCache.HybridCache() -> void
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableCompression = 32 -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableDistributedCache = Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableDistributedCacheRead | Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableDistributedCacheWrite -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableDistributedCacheRead = 4 -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableDistributedCacheWrite = 8 -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableLocalCache = Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableLocalCacheRead | Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableLocalCacheWrite -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableLocalCacheRead = 1 -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableLocalCacheWrite = 2 -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.DisableUnderlyingData = 16 -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags.None = 0 -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions.Expiration.get -> System.TimeSpan?
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions.Expiration.init -> void
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions.Flags.get -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryFlags?
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions.Flags.init -> void
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions.HybridCacheEntryOptions() -> void
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions.LocalCacheExpiration.get -> System.TimeSpan?
-Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions.LocalCacheExpiration.init -> void
 Microsoft.Extensions.Caching.Hybrid.HybridCacheOptions
 Microsoft.Extensions.Caching.Hybrid.HybridCacheOptions.DefaultEntryOptions.get -> Microsoft.Extensions.Caching.Hybrid.HybridCacheEntryOptions?
 Microsoft.Extensions.Caching.Hybrid.HybridCacheOptions.DefaultEntryOptions.set -> void
@@ -43,11 +13,6 @@ Microsoft.Extensions.Caching.Hybrid.HybridCacheOptions.ReportTagMetrics.get -> b
 Microsoft.Extensions.Caching.Hybrid.HybridCacheOptions.ReportTagMetrics.set -> void
 Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder
 Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
-Microsoft.Extensions.Caching.Hybrid.IHybridCacheSerializer<T>
-Microsoft.Extensions.Caching.Hybrid.IHybridCacheSerializer<T>.Deserialize(System.Buffers.ReadOnlySequence<byte> source) -> T
-Microsoft.Extensions.Caching.Hybrid.IHybridCacheSerializer<T>.Serialize(T value, System.Buffers.IBufferWriter<byte>! target) -> void
-Microsoft.Extensions.Caching.Hybrid.IHybridCacheSerializerFactory
-Microsoft.Extensions.Caching.Hybrid.IHybridCacheSerializerFactory.TryCreateSerializer<T>(out Microsoft.Extensions.Caching.Hybrid.IHybridCacheSerializer<T>? serializer) -> bool
 Microsoft.Extensions.DependencyInjection.HybridCacheBuilderExtensions
 Microsoft.Extensions.DependencyInjection.HybridCacheServiceExtensions
 static Microsoft.Extensions.DependencyInjection.HybridCacheBuilderExtensions.AddSerializer<T, TImplementation>(this Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder! builder) -> Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder!
@@ -56,5 +21,3 @@ static Microsoft.Extensions.DependencyInjection.HybridCacheBuilderExtensions.Add
 static Microsoft.Extensions.DependencyInjection.HybridCacheBuilderExtensions.AddSerializerFactory<TImplementation>(this Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder! builder) -> Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder!
 static Microsoft.Extensions.DependencyInjection.HybridCacheServiceExtensions.AddHybridCache(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder!
 static Microsoft.Extensions.DependencyInjection.HybridCacheServiceExtensions.AddHybridCache(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services, System.Action<Microsoft.Extensions.Caching.Hybrid.HybridCacheOptions!>! setupAction) -> Microsoft.Extensions.Caching.Hybrid.IHybridCacheBuilder!
-virtual Microsoft.Extensions.Caching.Hybrid.HybridCache.RemoveAsync(System.Collections.Generic.IEnumerable<string!>! keys, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask
-virtual Microsoft.Extensions.Caching.Hybrid.HybridCache.RemoveByTagAsync(System.Collections.Generic.IEnumerable<string!>! tags, System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.ValueTask
diff --git a/src/Caching/Hybrid/src/Runtime/HybridCache.cs b/src/Caching/Hybrid/src/Runtime/HybridCache.cs
deleted file mode 100644
index 8c239c82106d..000000000000
--- a/src/Caching/Hybrid/src/Runtime/HybridCache.cs
+++ /dev/null
@@ -1,128 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Extensions.Caching.Distributed;
-
-namespace Microsoft.Extensions.Caching.Hybrid;
-
-/// <summary>
-/// Provides multi-tier caching services building on <see cref="IDistributedCache"/> backends.
-/// </summary>
-public abstract class HybridCache
-{
-    /// <summary>
-    /// Asynchronously gets the value associated with the key if it exists, or generates a new entry using the provided key and a value from the given factory if the key is not found.
-    /// </summary>
-    /// <typeparam name="T">The type of the data being considered.</typeparam>
-    /// <typeparam name="TState">The type of additional state required by <paramref name="factory"/>.</typeparam>
-    /// <param name="key">The key of the entry to look for or create.</param>
-    /// <param name="factory">Provides the underlying data service is the data is not available in the cache.</param>
-    /// <param name="state">Additional state required for <paramref name="factory"/>.</param>
-    /// <param name="options">Additional options for this cache entry.</param>
-    /// <param name="tags">The tags to associate with this cache item.</param>
-    /// <param name="token">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
-    /// <returns>The data, either from cache or the underlying data service.</returns>
-    [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Delegate differences make this unambiguous")]
-    public abstract ValueTask<T> GetOrCreateAsync<TState, T>(string key, TState state, Func<TState, CancellationToken, ValueTask<T>> factory,
-        HybridCacheEntryOptions? options = null, IReadOnlyCollection<string>? tags = null, CancellationToken token = default);
-
-    /// <summary>
-    /// Asynchronously gets the value associated with the key if it exists, or generates a new entry using the provided key and a value from the given factory if the key is not found.
-    /// </summary>
-    /// <typeparam name="T">The type of the data being considered.</typeparam>
-    /// <param name="key">The key of the entry to look for or create.</param>
-    /// <param name="factory">Provides the underlying data service is the data is not available in the cache.</param>
-    /// <param name="options">Additional options for this cache entry.</param>
-    /// <param name="tags">The tags to associate with this cache item.</param>
-    /// <param name="token">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
-    /// <returns>The data, either from cache or the underlying data service.</returns>
-    [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Delegate differences make this unambiguous")]
-    public ValueTask<T> GetOrCreateAsync<T>(string key, Func<CancellationToken, ValueTask<T>> factory,
-        HybridCacheEntryOptions? options = null, IReadOnlyCollection<string>? tags = null, CancellationToken token = default)
-        => GetOrCreateAsync(key, factory, WrappedCallbackCache<T>.Instance, options, tags, token);
-
-    private static class WrappedCallbackCache<T> // per-T memoized helper that allows GetOrCreateAsync<T> and GetOrCreateAsync<TState, T> to share an implementation
-    {
-        // for the simple usage scenario (no TState), pack the original callback as the "state", and use a wrapper function that just unrolls and invokes from the state
-        public static readonly Func<Func<CancellationToken, ValueTask<T>>, CancellationToken, ValueTask<T>> Instance = static (callback, ct) => callback(ct);
-    }
-
-    /// <summary>
-    /// Asynchronously sets or overwrites the value associated with the key.
-    /// </summary>
-    /// <typeparam name="T">The type of the data being considered.</typeparam>
-    /// <param name="key">The key of the entry to create.</param>
-    /// <param name="value">The value to assign for this cache entry.</param>
-    /// <param name="options">Additional options for this cache entry.</param>
-    /// <param name="tags">The tags to associate with this cache entry.</param>
-    /// <param name="token">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
-    public abstract ValueTask SetAsync<T>(string key, T value, HybridCacheEntryOptions? options = null, IReadOnlyCollection<string>? tags = null, CancellationToken token = default);
-
-    /// <summary>
-    /// Asynchronously removes the value associated with the key if it exists.
-    /// </summary>
-    [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Not ambiguous in context")]
-    public abstract ValueTask RemoveAsync(string key, CancellationToken token = default);
-
-    /// <summary>
-    /// Asynchronously removes the value associated with the key if it exists.
-    /// </summary>
-    /// <remarks>Implementors should treat <c>null</c> as empty</remarks>
-    [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Not ambiguous in context")]
-    public virtual ValueTask RemoveAsync(IEnumerable<string> keys, CancellationToken token = default)
-    {
-        return keys switch
-        {
-            // for consistency with GetOrCreate/Set: interpret null as "none"
-            null or ICollection<string> { Count: 0 } => default,
-            ICollection<string> { Count: 1 } => RemoveAsync(keys.Single(), token),
-            _ => ForEachAsync(this, keys, token),
-        };
-
-        // default implementation is to call RemoveKeyAsync for each key in turn
-        static async ValueTask ForEachAsync(HybridCache @this, IEnumerable<string> keys, CancellationToken token)
-        {
-            foreach (var key in keys)
-            {
-                await @this.RemoveAsync(key, token).ConfigureAwait(false);
-            }
-        }
-    }
-
-    /// <summary>
-    /// Asynchronously removes all values associated with the specified tags.
-    /// </summary>
-    /// <remarks>Implementors should treat <c>null</c> as empty</remarks>
-    [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Not ambiguous in context")]
-    public virtual ValueTask RemoveByTagAsync(IEnumerable<string> tags, CancellationToken token = default)
-    {
-        return tags switch
-        {
-            // for consistency with GetOrCreate/Set: interpret null as "none"
-            null or ICollection<string> { Count: 0 } => default,
-            ICollection<string> { Count: 1 } => RemoveByTagAsync(tags.Single(), token),
-            _ => ForEachAsync(this, tags, token),
-        };
-
-        // default implementation is to call RemoveTagAsync for each key in turn
-        static async ValueTask ForEachAsync(HybridCache @this, IEnumerable<string> keys, CancellationToken token)
-        {
-            foreach (var key in keys)
-            {
-                await @this.RemoveByTagAsync(key, token).ConfigureAwait(false);
-            }
-        }
-    }
-
-    /// <summary>
-    /// Asynchronously removes all values associated with the specified tag.
-    /// </summary>
-    [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Not ambiguous in context")]
-    public abstract ValueTask RemoveByTagAsync(string tag, CancellationToken token = default);
-}
diff --git a/src/Caching/Hybrid/src/Runtime/HybridCacheEntryFlags.cs b/src/Caching/Hybrid/src/Runtime/HybridCacheEntryFlags.cs
deleted file mode 100644
index b6a51b11691f..000000000000
--- a/src/Caching/Hybrid/src/Runtime/HybridCacheEntryFlags.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-
-namespace Microsoft.Extensions.Caching.Hybrid;
-
-/// <summary>
-/// Additional flags that apply to a <see cref="HybridCache"/> operation.
-/// </summary>
-[Flags]
-public enum HybridCacheEntryFlags
-{
-    /// <summary>
-    /// No additional flags.
-    /// </summary>
-    None = 0,
-    /// <summary>
-    /// Disables reading from the local in-process cache.
-    /// </summary>
-    DisableLocalCacheRead = 1 << 0,
-    /// <summary>
-    /// Disables writing to the local in-process cache.
-    /// </summary>
-    DisableLocalCacheWrite = 1 << 1,
-    /// <summary>
-    /// Disables both reading from and writing to the local in-process cache.
-    /// </summary>
-    DisableLocalCache = DisableLocalCacheRead | DisableLocalCacheWrite,
-    /// <summary>
-    /// Disables reading from the secondary distributed cache.
-    /// </summary>
-    DisableDistributedCacheRead = 1 << 2,
-    /// <summary>
-    /// Disables writing to the secondary distributed cache.
-    /// </summary>
-    DisableDistributedCacheWrite = 1 << 3,
-    /// <summary>
-    /// Disables both reading from and writing to the secondary distributed cache.
-    /// </summary>
-    DisableDistributedCache = DisableDistributedCacheRead | DisableDistributedCacheWrite,
-    /// <summary>
-    /// Only fetches the value from cache; does not attempt to access the underlying data store.
-    /// </summary>
-    DisableUnderlyingData = 1 << 4,
-    /// <summary>
-    /// Disables compression for this payload.
-    /// </summary>
-    DisableCompression = 1 << 5,
-}
diff --git a/src/Caching/Hybrid/src/Runtime/HybridCacheEntryOptions.cs b/src/Caching/Hybrid/src/Runtime/HybridCacheEntryOptions.cs
deleted file mode 100644
index e5fd18b00699..000000000000
--- a/src/Caching/Hybrid/src/Runtime/HybridCacheEntryOptions.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using Microsoft.Extensions.Caching.Distributed;
-
-namespace Microsoft.Extensions.Caching.Hybrid;
-
-/// <summary>
-/// Additional options (expiration, etc.) that apply to a <see cref="HybridCache"/> operation. When options
-/// can be specified at multiple levels (for example, globally and per-call), the values are composed; the
-/// most granular non-null value is used, with null values being inherited. If no value is specified at
-/// any level, the implementation may choose a reasonable default.
-/// </summary>
-public sealed class HybridCacheEntryOptions
-{
-    /// <summary>
-    /// Overall cache duration of this entry, passed to the backend distributed cache.
-    /// </summary>
-    public TimeSpan? Expiration { get; init; } // overall cache duration
-
-    /// <summary>
-    /// Cache duration in local cache; when retrieving a cached value
-    /// from an external cache store, this value will be used to calculate the local
-    /// cache expiration, not exceeding the remaining overall cache lifetime.
-    /// </summary>
-    public TimeSpan? LocalCacheExpiration { get; init; } // TTL in L1
-
-    /// <summary>
-    /// Additional flags that apply to this usage.
-    /// </summary>
-    public HybridCacheEntryFlags? Flags { get; init; }
-
-    // memoize when possible
-    private DistributedCacheEntryOptions? _dc;
-    internal DistributedCacheEntryOptions? ToDistributedCacheEntryOptions()
-        => Expiration is null ? null : (_dc ??= new() { AbsoluteExpirationRelativeToNow = Expiration });
-}
diff --git a/src/Caching/Hybrid/src/Runtime/IBufferDistributedCache.cs b/src/Caching/Hybrid/src/Runtime/IBufferDistributedCache.cs
deleted file mode 100644
index 994d52766a9d..000000000000
--- a/src/Caching/Hybrid/src/Runtime/IBufferDistributedCache.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Buffers;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Microsoft.Extensions.Caching.Distributed; // intentional for parity with IDistributedCache
-
-/// <summary>
-/// Represents a distributed cache of serialized values, with support for low allocation data transfer.
-/// </summary>
-public interface IBufferDistributedCache : IDistributedCache
-{
-    /// <summary>
-    /// Attempt to retrieve an existing cache item.
-    /// </summary>
-    /// <param name="key">The unique key for the cache item.</param>
-    /// <param name="destination">The target to write the cache contents on success.</param>
-    /// <returns><c>true</c> if the cache item is found, <c>false</c> otherwise.</returns>
-    /// <remarks>This is functionally similar to <see cref="IDistributedCache.Get(string)"/>, but avoids the array allocation.</remarks>
-    bool TryGet(string key, IBufferWriter<byte> destination);
-
-    /// <summary>
-    /// Asynchronously attempt to retrieve an existing cache entry.
-    /// </summary>
-    /// <param name="key">The unique key for the cache entry.</param>
-    /// <param name="destination">The target to write the cache contents on success.</param>
-    /// <param name="token">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
-    /// <returns><c>true</c> if the cache entry is found, <c>false</c> otherwise.</returns>
-    /// <remarks>This is functionally similar to <see cref="IDistributedCache.GetAsync(string, CancellationToken)"/>, but avoids the array allocation.</remarks>
-    ValueTask<bool> TryGetAsync(string key, IBufferWriter<byte> destination, CancellationToken token = default);
-
-    /// <summary>
-    /// Sets or overwrites a cache item.
-    /// </summary>
-    /// <param name="key">The key of the entry to create.</param>
-    /// <param name="value">The value for this cache entry.</param>
-    /// <param name="options">The cache options for the entry.</param>
-    /// <remarks>This is functionally similar to <see cref="IDistributedCache.Set(string, byte[], DistributedCacheEntryOptions)"/>, but avoids the array allocation.</remarks>
-    void Set(string key, ReadOnlySequence<byte> value, DistributedCacheEntryOptions options);
-
-    /// <summary>
-    /// Asynchronously sets or overwrites a cache entry.
-    /// </summary>
-    /// <param name="key">The key of the entry to create.</param>
-    /// <param name="value">The value for this cache entry.</param>
-    /// <param name="options">The cache options for the value.</param>
-    /// <param name="token">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
-    /// <remarks>This is functionally similar to <see cref="IDistributedCache.SetAsync(string, byte[], DistributedCacheEntryOptions, CancellationToken)"/>, but avoids the array allocation.</remarks>
-    ValueTask SetAsync(string key, ReadOnlySequence<byte> value, DistributedCacheEntryOptions options, CancellationToken token = default);
-}
diff --git a/src/Caching/Hybrid/src/Runtime/IHybridCacheSerializer.cs b/src/Caching/Hybrid/src/Runtime/IHybridCacheSerializer.cs
deleted file mode 100644
index f5c869a71772..000000000000
--- a/src/Caching/Hybrid/src/Runtime/IHybridCacheSerializer.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Buffers;
-
-namespace Microsoft.Extensions.Caching.Hybrid;
-
-/// <summary>
-/// Per-type serialization/deserialization support for <see cref="HybridCache"/>.
-/// </summary>
-/// <typeparam name="T">The type being serialized/deserialized.</typeparam>
-public interface IHybridCacheSerializer<T>
-{
-    /// <summary>
-    /// Deserialize a <typeparamref name="T"/> value from the provided <paramref name="source"/>.
-    /// </summary>
-    T Deserialize(ReadOnlySequence<byte> source);
-
-    /// <summary>
-    /// Serialize <paramref name="value"/>, writing to the provided <paramref name="target"/>.
-    /// </summary>
-    void Serialize(T value, IBufferWriter<byte> target);
-}
-
diff --git a/src/Caching/Hybrid/src/Runtime/IHybridCacheSerializerFactory.cs b/src/Caching/Hybrid/src/Runtime/IHybridCacheSerializerFactory.cs
deleted file mode 100644
index d500ddfb2ba9..000000000000
--- a/src/Caching/Hybrid/src/Runtime/IHybridCacheSerializerFactory.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Diagnostics.CodeAnalysis;
-
-namespace Microsoft.Extensions.Caching.Hybrid;
-
-/// <summary>
-/// Factory provider for per-type <see cref="IHybridCacheSerializer{T}"/> instances.
-/// </summary>
-public interface IHybridCacheSerializerFactory
-{
-    /// <summary>
-    /// Request a serializer for the provided type, if possible.
-    /// </summary>
-    /// <typeparam name="T">The type being serialized/deserialized.</typeparam>
-    /// <param name="serializer">The serializer.</param>
-    /// <returns><c>true</c> if the factory supports this type, <c>false</c> otherwise.</returns>
-    bool TryCreateSerializer<T>([NotNullWhen(true)] out IHybridCacheSerializer<T>? serializer);
-}
diff --git a/src/Caching/Hybrid/src/Runtime/readme.md b/src/Caching/Hybrid/src/Runtime/readme.md
deleted file mode 100644
index 1e2289449f0b..000000000000
--- a/src/Caching/Hybrid/src/Runtime/readme.md
+++ /dev/null
@@ -1,2 +0,0 @@
-These types are intended to be added to be relocated to `Microsoft.Extensions.Caching.Abstractions`; their inclusion
-here is a preview placeholder
diff --git a/src/Caching/Hybrid/test/L2Tests.cs b/src/Caching/Hybrid/test/L2Tests.cs
index 6fd77c0707a6..378e5c8ed4ba 100644
--- a/src/Caching/Hybrid/test/L2Tests.cs
+++ b/src/Caching/Hybrid/test/L2Tests.cs
@@ -38,7 +38,9 @@ static string CreateString(bool work = false)
         return Guid.NewGuid().ToString();
     }
 
-    static readonly HybridCacheEntryOptions _noL1 = new() { Flags = HybridCacheEntryFlags.DisableLocalCache };
+    private static readonly HybridCacheEntryOptions Expiry = new() { Expiration = TimeSpan.FromMinutes(3.5) };
+
+    private static readonly HybridCacheEntryOptions ExpiryNoL1 = new() { Flags = HybridCacheEntryFlags.DisableLocalCache, Expiration = TimeSpan.FromMinutes(3.5) };
 
     [Theory]
     [InlineData(true)]
@@ -63,7 +65,7 @@ public async Task AssertL2Operations_Immutable(bool buffers)
         Log.WriteLine("Reading without L1...");
         for (var i = 0; i < 5; i++)
         {
-            var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask<string>(CreateString()), _noL1);
+            var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask<string>(CreateString()), ExpiryNoL1);
             Assert.Equal(s, x);
             Assert.NotSame(s, x);
         }
@@ -103,13 +105,13 @@ public async Task AssertL2Operations_Mutable(bool buffers)
         using var provider = GetDefaultCache(buffers, out var cache);
         var backend = Assert.IsAssignableFrom<LoggingCache>(cache.BackendCache);
         Log.WriteLine("Inventing key...");
-        var s = await cache.GetOrCreateAsync(Me(), ct => new ValueTask<Foo>(new Foo { Value = CreateString(true) }));
+        var s = await cache.GetOrCreateAsync(Me(), ct => new ValueTask<Foo>(new Foo { Value = CreateString(true) }), Expiry);
         Assert.Equal(2, backend.OpCount); // GET, SET
 
         Log.WriteLine("Reading with L1...");
         for (var i = 0; i < 5; i++)
         {
-            var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask<Foo>(new Foo { Value = CreateString() }));
+            var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask<Foo>(new Foo { Value = CreateString() }), Expiry);
             Assert.Equal(s.Value, x.Value);
             Assert.NotSame(s, x);
         }
@@ -118,7 +120,7 @@ public async Task AssertL2Operations_Mutable(bool buffers)
         Log.WriteLine("Reading without L1...");
         for (var i = 0; i < 5; i++)
         {
-            var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask<Foo>(new Foo { Value = CreateString() }), _noL1);
+            var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask<Foo>(new Foo { Value = CreateString() }), ExpiryNoL1);
             Assert.Equal(s.Value, x.Value);
             Assert.NotSame(s, x);
         }
@@ -129,7 +131,7 @@ public async Task AssertL2Operations_Mutable(bool buffers)
         await cache.SetAsync(Me(), s);
         for (var i = 0; i < 5; i++)
         {
-            var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask<Foo>(new Foo { Value = CreateString() }));
+            var x = await cache.GetOrCreateAsync(Me(), ct => new ValueTask<Foo>(new Foo { Value = CreateString() }), Expiry);
             Assert.Equal(s.Value, x.Value);
             Assert.NotSame(s, x);
         }
@@ -140,7 +142,7 @@ public async Task AssertL2Operations_Mutable(bool buffers)
         Assert.Equal(9, backend.OpCount); // DEL
 
         Log.WriteLine("Fetching new...");
-        var t = await cache.GetOrCreateAsync(Me(), ct => new ValueTask<Foo>(new Foo { Value = CreateString(true) }));
+        var t = await cache.GetOrCreateAsync(Me(), ct => new ValueTask<Foo>(new Foo { Value = CreateString(true) }), Expiry);
         Assert.NotEqual(s.Value, t.Value);
         Assert.Equal(11, backend.OpCount); // GET, SET
     }
diff --git a/src/Caching/Hybrid/test/Microsoft.Extensions.Caching.Hybrid.Tests.csproj b/src/Caching/Hybrid/test/Microsoft.Extensions.Caching.Hybrid.Tests.csproj
index 54c0de3adf67..4b862961ffa3 100644
--- a/src/Caching/Hybrid/test/Microsoft.Extensions.Caching.Hybrid.Tests.csproj
+++ b/src/Caching/Hybrid/test/Microsoft.Extensions.Caching.Hybrid.Tests.csproj
@@ -7,6 +7,7 @@
   </PropertyGroup>
 
   <ItemGroup>
+    <Reference Include="Microsoft.Extensions.Caching.Abstractions" />
     <Reference Include="Microsoft.Extensions.Caching.Hybrid" />
     <Reference Include="Microsoft.Extensions.Configuration.Json" />
     <Reference Include="Microsoft.Extensions.Caching.StackExchangeRedis" />
diff --git a/src/Caching/Hybrid/test/SampleUsage.cs b/src/Caching/Hybrid/test/SampleUsage.cs
index 8d65d5aeff9f..78786a8b8877 100644
--- a/src/Caching/Hybrid/test/SampleUsage.cs
+++ b/src/Caching/Hybrid/test/SampleUsage.cs
@@ -121,7 +121,7 @@ public async Task<SomeInformation> GetSomeInformationAsync(string name, int id,
             return await cache.GetOrCreateAsync(
                 $"someinfo:{name}:{id}", // unique key for this combination
                 async ct => await SomeExpensiveOperationAsync(name, id, ct),
-                token: token
+                cancellationToken: token
                 );
         }
     }
@@ -147,7 +147,7 @@ public async Task<SomeInformation> GetSomeInformationAsync(string name, int id,
                 (name, id), // all of the state we need for the final call, if needed
                 static async (state, token) =>
                     await SomeExpensiveOperationAsync(state.name, state.id, token),
-                token: token
+                cancellationToken: token
             );
         }
     }
@@ -161,7 +161,7 @@ public async Task<SomeInformationReuse> GetSomeInformationAsync(string name, int
                 (name, id), // all of the state we need for the final call, if needed
                 static async (state, token) =>
                     await SomeExpensiveOperationReuseAsync(state.name, state.id, token),
-                token: token
+                cancellationToken: token
             );
         }
     }
diff --git a/src/Caching/Hybrid/test/StampedeTests.cs b/src/Caching/Hybrid/test/StampedeTests.cs
index 6fd4bab51f91..bfd777954566 100644
--- a/src/Caching/Hybrid/test/StampedeTests.cs
+++ b/src/Caching/Hybrid/test/StampedeTests.cs
@@ -87,7 +87,7 @@ public async Task MultipleCallsShareExecution_NoCancellation(int callerCount, bo
                 Interlocked.Increment(ref executeCount);
                 ct.ThrowIfCancellationRequested(); // assert not cancelled
                 return Guid.NewGuid();
-            }, token: token).AsTask();
+            }, cancellationToken: token).AsTask();
         }
 
         Assert.Equal(callerCount, cache.DebugGetCallerCount(Me()));
@@ -121,7 +121,7 @@ public async Task MultipleCallsShareExecution_NoCancellation(int callerCount, bo
                 Interlocked.Increment(ref executeCount);
                 ct.ThrowIfCancellationRequested(); // assert not cancelled
                 return Guid.NewGuid();
-            }, token: token).AsTask();
+            }, cancellationToken: token).AsTask();
         }
 
         Assert.Equal(callerCount, cache.DebugGetCallerCount(Me()));
@@ -178,7 +178,7 @@ public async Task MultipleCallsShareExecution_EveryoneCancels(int callerCount)
                 {
                     semaphore.Release(); // handshake so we can check when available again
                 }
-            }, token: cancels[i].Token).AsTask();
+            }, cancellationToken: cancels[i].Token).AsTask();
         }
 
         Assert.Equal(callerCount, cache.DebugGetCallerCount(Me()));
@@ -250,7 +250,7 @@ public async Task MultipleCallsShareExecution_MostCancel(int callerCount, int re
                 {
                     semaphore.Release(); // handshake so we can check when available again
                 }
-            }, token: cancels[i].Token).AsTask();
+            }, cancellationToken: cancels[i].Token).AsTask();
         }
 
         Assert.Equal(callerCount, cache.DebugGetCallerCount(Me()));
@@ -299,8 +299,8 @@ public async Task ImmutableTypesShareFinalTask(bool withCancelation)
         using var semaphore = new SemaphoreSlim(0);
 
         // note AsTask *in this scenario* fetches the underlying incomplete task
-        var first = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return Guid.NewGuid(); }, token: token).AsTask();
-        var second = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return Guid.NewGuid(); }, token: token).AsTask();
+        var first = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return Guid.NewGuid(); }, cancellationToken: token).AsTask();
+        var second = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return Guid.NewGuid(); }, cancellationToken: token).AsTask();
 
         if (withCancelation)
         {
@@ -325,8 +325,8 @@ public async Task ImmutableCustomTypesShareFinalTask(bool withCancelation)
         using var semaphore = new SemaphoreSlim(0);
 
         // AsTask *in this scenario* fetches the underlying incomplete task
-        var first = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Immutable(Guid.NewGuid()); }, token: token).AsTask();
-        var second = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Immutable(Guid.NewGuid()); }, token: token).AsTask();
+        var first = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Immutable(Guid.NewGuid()); }, cancellationToken: token).AsTask();
+        var second = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Immutable(Guid.NewGuid()); }, cancellationToken: token).AsTask();
 
         if (withCancelation)
         {
@@ -355,8 +355,8 @@ public async Task MutableTypesNeverShareFinalTask(bool withCancelation)
         using var semaphore = new SemaphoreSlim(0);
 
         // AsTask *in this scenario* fetches the underlying incomplete task
-        var first = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Mutable(Guid.NewGuid()); }, token: token).AsTask();
-        var second = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Mutable(Guid.NewGuid()); }, token: token).AsTask();
+        var first = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Mutable(Guid.NewGuid()); }, cancellationToken: token).AsTask();
+        var second = cache.GetOrCreateAsync(Me(), async ct => { await semaphore.WaitAsync(CancellationToken.None); semaphore.Release(); return new Mutable(Guid.NewGuid()); }, cancellationToken: token).AsTask();
 
         Assert.NotSame(first, second);
         semaphore.Release();
diff --git a/src/Caching/SqlServer/src/Microsoft.Extensions.Caching.SqlServer.csproj b/src/Caching/SqlServer/src/Microsoft.Extensions.Caching.SqlServer.csproj
index 21c98b778833..3088ff699532 100644
--- a/src/Caching/SqlServer/src/Microsoft.Extensions.Caching.SqlServer.csproj
+++ b/src/Caching/SqlServer/src/Microsoft.Extensions.Caching.SqlServer.csproj
@@ -20,9 +20,6 @@
     <Reference Include="Microsoft.Extensions.Options" />
     <Reference Include="Microsoft.Data.SqlClient" />
     <Reference Include="Azure.Identity" />
-
-    <!-- temporary until we can move IBufferDistributedCache to Microsoft.Extensions.Caching.Abstractions-->
-    <Reference Include="Microsoft.Extensions.Caching.Hybrid" />
   </ItemGroup>
 
   <ItemGroup>
diff --git a/src/Caching/StackExchangeRedis/src/Microsoft.Extensions.Caching.StackExchangeRedis.csproj b/src/Caching/StackExchangeRedis/src/Microsoft.Extensions.Caching.StackExchangeRedis.csproj
index 3a3faeaf9f40..c3f7de250341 100644
--- a/src/Caching/StackExchangeRedis/src/Microsoft.Extensions.Caching.StackExchangeRedis.csproj
+++ b/src/Caching/StackExchangeRedis/src/Microsoft.Extensions.Caching.StackExchangeRedis.csproj
@@ -15,9 +15,6 @@
     <Reference Include="Microsoft.Extensions.Logging.Abstractions" />
     <Reference Include="Microsoft.Extensions.Options" />
     <Reference Include="StackExchange.Redis" />
-
-    <!-- temporary until we can move IBufferDistributedCache to Microsoft.Extensions.Caching.Abstractions-->
-    <Reference Include="Microsoft.Extensions.Caching.Hybrid" />
   </ItemGroup>
 
   <ItemGroup>
diff --git a/src/Caching/perf/MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks.csproj b/src/Caching/perf/MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks.csproj
index 50b8df19317e..40a058e7dc13 100644
--- a/src/Caching/perf/MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks.csproj
+++ b/src/Caching/perf/MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks/Microsoft.Extensions.Caching.MicroBenchmarks.csproj
@@ -16,6 +16,8 @@
     <Reference Include="Microsoft.Extensions.Caching.StackExchangeRedis" />
     <Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
     <Reference Include="Microsoft.Extensions.DependencyInjection" />
+    <Reference Include="Microsoft.Extensions.Caching.Hybrid" />
+
 
     <Compile Include="..\..\..\Hybrid\src\Internal\RecyclableArrayBufferWriter.cs" LinkBase="Microsoft.Extensions.Caching.Hybrid" />
     <!--<Compile Include="$(SharedSourceRoot)BenchmarkRunner\*.cs" />-->