make ServerCallContext an abstract base class
diff --git a/src/csharp/Grpc.Core.Testing/TestServerCallContext.cs b/src/csharp/Grpc.Core.Testing/TestServerCallContext.cs
index d72e98e..7a4fb15 100644
--- a/src/csharp/Grpc.Core.Testing/TestServerCallContext.cs
+++ b/src/csharp/Grpc.Core.Testing/TestServerCallContext.cs
@@ -36,12 +36,73 @@
             string peer, AuthContext authContext, ContextPropagationToken contextPropagationToken,
             Func<Metadata, Task> writeHeadersFunc, Func<WriteOptions> writeOptionsGetter, Action<WriteOptions> writeOptionsSetter)
         {
-            return new ServerCallContext(null, method, host, deadline, requestHeaders, cancellationToken,
-                (ctx, extraData, headers) => writeHeadersFunc(headers),
-                (ctx, extraData) => writeOptionsGetter(),
-                (ctx, extraData, options) => writeOptionsSetter(options),
-                (ctx, extraData) => peer, (ctx, callHandle) => authContext,
-                (ctx, callHandle, options) => contextPropagationToken);
+            return new TestingServerCallContext(method, host, deadline, requestHeaders, cancellationToken, peer,
+                authContext, contextPropagationToken, writeHeadersFunc, writeOptionsGetter, writeOptionsSetter);
+        }
+
+        private class TestingServerCallContext : ServerCallContext
+        {
+            private readonly string method;
+            private readonly string host;
+            private readonly DateTime deadline;
+            private readonly Metadata requestHeaders;
+            private readonly CancellationToken cancellationToken;
+            private readonly Metadata responseTrailers = new Metadata();
+            private Status status;
+            private readonly string peer;
+            private readonly AuthContext authContext;
+            private readonly ContextPropagationToken contextPropagationToken;
+            private readonly Func<Metadata, Task> writeHeadersFunc;
+            private readonly Func<WriteOptions> writeOptionsGetter;
+            private readonly Action<WriteOptions> writeOptionsSetter;
+
+            public TestingServerCallContext(string method, string host, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken,
+                string peer, AuthContext authContext, ContextPropagationToken contextPropagationToken,
+                Func<Metadata, Task> writeHeadersFunc, Func<WriteOptions> writeOptionsGetter, Action<WriteOptions> writeOptionsSetter)
+            {
+                this.method = method;
+                this.host = host;
+                this.deadline = deadline;
+                this.requestHeaders = requestHeaders;
+                this.cancellationToken = cancellationToken;
+                this.responseTrailers = new Metadata();
+                this.status = Status.DefaultSuccess;
+                this.peer = peer;
+                this.authContext = authContext;
+                this.contextPropagationToken = contextPropagationToken;
+                this.writeHeadersFunc = writeHeadersFunc;
+                this.writeOptionsGetter = writeOptionsGetter;
+                this.writeOptionsSetter = writeOptionsSetter;
+            }
+
+            protected override string MethodInternal => method;
+
+            protected override string HostInternal => host;
+
+            protected override string PeerInternal => peer;
+
+            protected override DateTime DeadlineInternal => deadline;
+
+            protected override Metadata RequestHeadersInternal => requestHeaders;
+
+            protected override CancellationToken CancellationTokenInternal => cancellationToken;
+
+            protected override Metadata ResponseTrailersInternal => responseTrailers;
+
+            protected override Status StatusInternal { get => status; set => status = value; }
+            protected override WriteOptions WriteOptionsInternal { get => writeOptionsGetter(); set => writeOptionsSetter(value); }
+
+            protected override AuthContext AuthContextInternal => authContext;
+
+            protected override ContextPropagationToken CreatePropagationTokenInternal(ContextPropagationOptions options)
+            {
+                return contextPropagationToken;
+            }
+
+            protected override Task WriteResponseHeadersInternalAsync(Metadata responseHeaders)
+            {
+                return writeHeadersFunc(responseHeaders);
+            }
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/Internal/DefaultServerCallContext.cs b/src/csharp/Grpc.Core/Internal/DefaultServerCallContext.cs
new file mode 100644
index 0000000..1e484bd
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/DefaultServerCallContext.cs
@@ -0,0 +1,111 @@
+#region Copyright notice and license
+
+// Copyright 2019 The gRPC 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
+//
+//     http://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.
+
+#endregion
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Grpc.Core.Internal;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core
+{
+    /// <summary>
+    /// Default implementation of <c>ServerCallContext</c>.
+    /// </summary>
+    internal class DefaultServerCallContext : ServerCallContext
+    {
+        private readonly CallSafeHandle callHandle;
+        private readonly string method;
+        private readonly string host;
+        private readonly DateTime deadline;
+        private readonly Metadata requestHeaders;
+        private readonly CancellationToken cancellationToken;
+        private readonly Metadata responseTrailers;
+        private Status status;
+        private readonly IServerResponseStream serverResponseStream;
+        private readonly Lazy<AuthContext> authContext;
+
+        /// <summary>
+        /// Creates a new instance of <c>ServerCallContext</c>.
+        /// To allow reuse of ServerCallContext API by different gRPC implementations, the implementation of some members is provided externally.
+        /// To provide state, this <c>ServerCallContext</c> instance and <c>extraData</c> will be passed to the member implementations.
+        /// </summary>
+        internal DefaultServerCallContext(CallSafeHandle callHandle, string method, string host, DateTime deadline,
+            Metadata requestHeaders, CancellationToken cancellationToken, IServerResponseStream serverResponseStream)
+        {
+            this.callHandle = callHandle;
+            this.method = method;
+            this.host = host;
+            this.deadline = deadline;
+            this.requestHeaders = requestHeaders;
+            this.cancellationToken = cancellationToken;
+            this.responseTrailers = new Metadata();
+            this.status = Status.DefaultSuccess;
+            this.serverResponseStream = serverResponseStream;
+            // TODO(jtattermusch): avoid unnecessary allocation of factory function and the lazy object
+            this.authContext = new Lazy<AuthContext>(GetAuthContextEager);
+        }
+
+        protected override ContextPropagationToken CreatePropagationTokenInternal(ContextPropagationOptions options)
+        {
+            return new ContextPropagationToken(callHandle, deadline, cancellationToken, options);
+        }
+
+        protected override Task WriteResponseHeadersInternalAsync(Metadata responseHeaders)
+        {
+            return serverResponseStream.WriteResponseHeadersAsync(responseHeaders);
+        }
+
+        protected override string MethodInternal => method;
+
+        protected override string HostInternal => host;
+
+        protected override string PeerInternal => callHandle.GetPeer();
+
+        protected override DateTime DeadlineInternal => deadline;
+
+        protected override Metadata RequestHeadersInternal => requestHeaders;
+
+        protected override CancellationToken CancellationTokenInternal => cancellationToken;
+
+        protected override Metadata ResponseTrailersInternal => responseTrailers;
+
+        protected override Status StatusInternal
+        {
+            get => status;
+            set => status = value;
+        }
+
+        protected override WriteOptions WriteOptionsInternal
+        {
+            get => serverResponseStream.WriteOptions;
+            set => serverResponseStream.WriteOptions = value;
+        }
+
+        protected override AuthContext AuthContextInternal => authContext.Value;
+
+        private AuthContext GetAuthContextEager()
+        {
+            using (var authContextNative = callHandle.GetAuthContext())
+            {
+                return authContextNative.ToAuthContext();
+            }
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Internal/ServerCallContextExtraData.cs b/src/csharp/Grpc.Core/Internal/ServerCallContextExtraData.cs
deleted file mode 100644
index 97b95e6..0000000
--- a/src/csharp/Grpc.Core/Internal/ServerCallContextExtraData.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-#region Copyright notice and license
-
-// Copyright 2019 The gRPC 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
-//
-//     http://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.
-
-#endregion
-
-using System;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Grpc.Core.Internal
-{
-    /// <summary>
-    /// Additional state for <c>ServerCallContext</c>.
-    /// Storing the extra state outside of <c>ServerCallContext</c> allows it to be implementation-agnostic.
-    /// </summary>
-    internal class ServerCallContextExtraData
-    {
-        readonly CallSafeHandle callHandle;
-        readonly IServerResponseStream serverResponseStream;
-        readonly Lazy<AuthContext> cachedAuthContext;
-
-        public ServerCallContextExtraData(CallSafeHandle callHandle, IServerResponseStream serverResponseStream)
-        {
-            this.callHandle = callHandle;
-            this.serverResponseStream = serverResponseStream;
-            // TODO(jtattermusch): avoid unnecessary allocation of factory function and the lazy object.
-            this.cachedAuthContext = new Lazy<AuthContext>(GetAuthContextEager);
-        }
-
-        public ServerCallContext NewServerCallContext(ServerRpcNew newRpc, CancellationToken cancellationToken)
-        {
-            DateTime realtimeDeadline = newRpc.Deadline.ToClockType(ClockType.Realtime).ToDateTime();
-
-            return new ServerCallContext(this, newRpc.Method, newRpc.Host, realtimeDeadline,
-                newRpc.RequestMetadata, cancellationToken,
-                ServerCallContext_WriteHeadersFunc, ServerCallContext_WriteOptionsGetter, ServerCallContext_WriteOptionsSetter,
-                ServerCallContext_PeerGetter, ServerCallContext_AuthContextGetter, ServerCallContext_ContextPropagationTokenFactory);
-        }
-
-        private AuthContext GetAuthContextEager()
-        {
-            using (var authContextNative = callHandle.GetAuthContext())
-            {
-                return authContextNative.ToAuthContext();
-            }
-        }
-
-        // Implementors of ServerCallContext's members are pre-allocated to avoid unneccessary delegate allocations.
-        readonly static Func<ServerCallContext, object, Metadata, Task> ServerCallContext_WriteHeadersFunc = (ctx, extraData, headers) =>
-        {
-            return ((ServerCallContextExtraData)extraData).serverResponseStream.WriteResponseHeadersAsync(headers);
-        };
-
-        readonly static Func<ServerCallContext, object, WriteOptions> ServerCallContext_WriteOptionsGetter = (ctx, extraData) =>
-        {
-
-            return ((ServerCallContextExtraData)extraData).serverResponseStream.WriteOptions;
-        };
-
-        readonly static Action<ServerCallContext, object, WriteOptions> ServerCallContext_WriteOptionsSetter = (ctx, extraData, options) =>
-        {
-            ((ServerCallContextExtraData)extraData).serverResponseStream.WriteOptions = options;
-        };
-
-        readonly static Func<ServerCallContext, object, string> ServerCallContext_PeerGetter = (ctx, extraData) =>
-        {
-            // Getting the peer lazily is fine as the native call is guaranteed
-            // not to be disposed before user-supplied server side handler returns.
-            // Most users won't need to read this field anyway.
-            return ((ServerCallContextExtraData)extraData).callHandle.GetPeer();
-        };
-
-        readonly static Func<ServerCallContext, object, AuthContext> ServerCallContext_AuthContextGetter = (ctx, extraData) =>
-        {
-            return ((ServerCallContextExtraData)extraData).cachedAuthContext.Value;
-        };
-
-        readonly static Func<ServerCallContext, object, ContextPropagationOptions, ContextPropagationToken> ServerCallContext_ContextPropagationTokenFactory = (ctx, extraData, options) =>
-        {
-            var callHandle = ((ServerCallContextExtraData)extraData).callHandle;
-            return new ContextPropagationToken(callHandle, ctx.Deadline, ctx.CancellationToken, options);
-        };
-    }
-}
diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
index ae586f7..c3859f1 100644
--- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs
@@ -348,9 +348,7 @@
         public static ServerCallContext NewContext(ServerRpcNew newRpc, IServerResponseStream serverResponseStream, CancellationToken cancellationToken)
         {
             DateTime realtimeDeadline = newRpc.Deadline.ToClockType(ClockType.Realtime).ToDateTime();
-
-            var contextExtraData = new ServerCallContextExtraData(newRpc.Call, serverResponseStream);
-            return contextExtraData.NewServerCallContext(newRpc, cancellationToken);
+            return new DefaultServerCallContext(newRpc.Call, newRpc.Method, newRpc.Host, realtimeDeadline, newRpc.RequestMetadata, cancellationToken, serverResponseStream);
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/ServerCallContext.cs b/src/csharp/Grpc.Core/ServerCallContext.cs
index 05c20ca..4a2fdf3 100644
--- a/src/csharp/Grpc.Core/ServerCallContext.cs
+++ b/src/csharp/Grpc.Core/ServerCallContext.cs
@@ -28,51 +28,13 @@
     /// <summary>
     /// Context for a server-side call.
     /// </summary>
-    public class ServerCallContext
+    public abstract class ServerCallContext
     {
-        private readonly object extraData;
-        private readonly string method;
-        private readonly string host;
-        private readonly DateTime deadline;
-        private readonly Metadata requestHeaders;
-        private readonly CancellationToken cancellationToken;
-        private readonly Metadata responseTrailers = new Metadata();
-        private readonly Func<ServerCallContext, object, Metadata, Task> writeHeadersFunc;
-        private readonly Func<ServerCallContext, object, WriteOptions> writeOptionsGetter;
-        private readonly Action<ServerCallContext, object, WriteOptions> writeOptionsSetter;
-
-        private readonly Func<ServerCallContext, object, string> peerGetter;
-        private readonly Func<ServerCallContext, object, AuthContext> authContextGetter;
-        private readonly Func<ServerCallContext, object, ContextPropagationOptions, ContextPropagationToken> contextPropagationTokenFactory;
-
-        private Status status = Status.DefaultSuccess;
-
         /// <summary>
         /// Creates a new instance of <c>ServerCallContext</c>.
-        /// To allow reuse of ServerCallContext API by different gRPC implementations, the implementation of some members is provided externally.
-        /// To provide state, this <c>ServerCallContext</c> instance and <c>extraData</c> will be passed to the member implementations.
         /// </summary>
-        internal ServerCallContext(object extraData,
-            string method, string host, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken,
-            Func<ServerCallContext, object, Metadata, Task> writeHeadersFunc,
-            Func<ServerCallContext, object, WriteOptions> writeOptionsGetter,
-            Action<ServerCallContext, object, WriteOptions> writeOptionsSetter,
-            Func<ServerCallContext, object, string> peerGetter,
-            Func<ServerCallContext, object, AuthContext> authContextGetter,
-            Func<ServerCallContext, object, ContextPropagationOptions, ContextPropagationToken> contextPropagationTokenFactory)
+        protected ServerCallContext()
         {
-            this.extraData = extraData;
-            this.method = method;
-            this.host = host;
-            this.deadline = deadline;
-            this.requestHeaders = requestHeaders;
-            this.cancellationToken = cancellationToken;
-            this.writeHeadersFunc = GrpcPreconditions.CheckNotNull(writeHeadersFunc);
-            this.writeOptionsGetter = GrpcPreconditions.CheckNotNull(writeOptionsGetter);
-            this.writeOptionsSetter = GrpcPreconditions.CheckNotNull(writeOptionsSetter);
-            this.peerGetter = GrpcPreconditions.CheckNotNull(peerGetter);
-            this.authContextGetter = GrpcPreconditions.CheckNotNull(authContextGetter);
-            this.contextPropagationTokenFactory = GrpcPreconditions.CheckNotNull(contextPropagationTokenFactory);
         }
 
         /// <summary>
@@ -84,7 +46,7 @@
         /// <returns>The task that finished once response headers have been written.</returns>
         public Task WriteResponseHeadersAsync(Metadata responseHeaders)
         {
-            return writeHeadersFunc(this, extraData, responseHeaders);
+            return WriteResponseHeadersInternalAsync(responseHeaders);
         }
 
         /// <summary>
@@ -92,83 +54,41 @@
         /// </summary>
         public ContextPropagationToken CreatePropagationToken(ContextPropagationOptions options = null)
         {
-            return contextPropagationTokenFactory(this, extraData, options);
+            return CreatePropagationTokenInternal(options);
         }
 
         /// <summary>Name of method called in this RPC.</summary>
-        public string Method
-        {
-            get
-            {
-                return this.method;
-            }
-        }
+        public string Method => MethodInternal;
 
         /// <summary>Name of host called in this RPC.</summary>
-        public string Host
-        {
-            get
-            {
-                return this.host;
-            }
-        }
+        public string Host => HostInternal;
 
         /// <summary>Address of the remote endpoint in URI format.</summary>
-        public string Peer
-        {
-            get
-            {
-                return peerGetter(this, extraData);
-            }
-        }
+        public string Peer => PeerInternal;
 
         /// <summary>Deadline for this RPC.</summary>
-        public DateTime Deadline
-        {
-            get
-            {
-                return this.deadline;
-            }
-        }
+        public DateTime Deadline => DeadlineInternal;
 
         /// <summary>Initial metadata sent by client.</summary>
-        public Metadata RequestHeaders
-        {
-            get
-            {
-                return this.requestHeaders;
-            }
-        }
+        public Metadata RequestHeaders => RequestHeadersInternal;
 
         /// <summary>Cancellation token signals when call is cancelled.</summary>
-        public CancellationToken CancellationToken
-        {
-            get
-            {
-                return this.cancellationToken;
-            }
-        }
+        public CancellationToken CancellationToken => CancellationTokenInternal;
 
         /// <summary>Trailers to send back to client after RPC finishes.</summary>
-        public Metadata ResponseTrailers
-        {
-            get
-            {
-                return this.responseTrailers;
-            }
-        }
+        public Metadata ResponseTrailers => ResponseTrailersInternal;
 
         /// <summary> Status to send back to client after RPC finishes.</summary>
         public Status Status
         {
             get
             {
-                return this.status;
+                return StatusInternal;
             }
 
             set
             {
-                status = value;
+                StatusInternal = value;
             }
         }
 
@@ -181,12 +101,12 @@
         {
             get
             {
-                return writeOptionsGetter(this, extraData);
+                return WriteOptionsInternal;
             }
 
             set
             {
-                writeOptionsSetter(this, extraData, value);
+                WriteOptionsInternal = value;
             }
         }
 
@@ -194,12 +114,31 @@
         /// Gets the <c>AuthContext</c> associated with this call.
         /// Note: Access to AuthContext is an experimental API that can change without any prior notice.
         /// </summary>
-        public AuthContext AuthContext
-        {
-            get
-            {
-                return authContextGetter(this, extraData);
-            }
-        }
+        public AuthContext AuthContext => AuthContextInternal;
+
+        /// <summary>Provides implementation of a non-virtual public member.</summary>
+        protected abstract Task WriteResponseHeadersInternalAsync(Metadata responseHeaders);
+        /// <summary>Provides implementation of a non-virtual public member.</summary>
+        protected abstract ContextPropagationToken CreatePropagationTokenInternal(ContextPropagationOptions options);
+        /// <summary>Provides implementation of a non-virtual public member.</summary>
+        protected abstract string MethodInternal { get; }
+        /// <summary>Provides implementation of a non-virtual public member.</summary>
+        protected abstract string HostInternal { get; }
+        /// <summary>Provides implementation of a non-virtual public member.</summary>
+        protected abstract string PeerInternal { get; }
+        /// <summary>Provides implementation of a non-virtual public member.</summary>
+        protected abstract DateTime DeadlineInternal { get; }
+        /// <summary>Provides implementation of a non-virtual public member.</summary>
+        protected abstract Metadata RequestHeadersInternal { get; }
+        /// <summary>Provides implementation of a non-virtual public member.</summary>
+        protected abstract CancellationToken CancellationTokenInternal { get; }
+        /// <summary>Provides implementation of a non-virtual public member.</summary>
+        protected abstract Metadata ResponseTrailersInternal { get; }
+        /// <summary>Provides implementation of a non-virtual public member.</summary>
+        protected abstract Status StatusInternal { get; set; }
+        /// <summary>Provides implementation of a non-virtual public member.</summary>
+        protected abstract WriteOptions WriteOptionsInternal { get; set; }
+          /// <summary>Provides implementation of a non-virtual public member.</summary>
+        protected abstract AuthContext AuthContextInternal { get; }
     }
 }