diff --git a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
index 7e2f0e9c6c9ed4803309e76e1a2cdc459d9ae892..a4aa8d3ffe42b37d6ca6234e2480be18f783cb71 100644
--- a/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
+++ b/src/csharp/Grpc.Core/Internal/CompletionRegistry.cs
@@ -51,7 +51,7 @@ namespace Grpc.Core.Internal
         static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<CompletionRegistry>();
 
         readonly GrpcEnvironment environment;
-        readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>();
+        readonly ConcurrentDictionary<IntPtr, OpCompletionDelegate> dict = new ConcurrentDictionary<IntPtr, OpCompletionDelegate>(new IntPtrComparer());
 
         public CompletionRegistry(GrpcEnvironment environment)
         {
@@ -121,5 +121,21 @@ namespace Grpc.Core.Internal
                 }
             }
         }
+
+        /// <summary>
+        /// IntPtr doesn't implement <c>IEquatable{IntPtr}</c> so we need to use custom comparer to avoid boxing.
+        /// </summary>
+        private class IntPtrComparer : IEqualityComparer<IntPtr>
+        {
+            public bool Equals(IntPtr x, IntPtr y)
+            {
+                return x == y;
+            }
+
+            public int GetHashCode(IntPtr obj)
+            {
+                return obj.GetHashCode();
+            }
+        }
     }
 }