diff --git a/.gitignore b/.gitignore
index b354350d1b65896cb210b215e1883c4828e92544..9868dcd32900cbad5b4d11bb01efb9a8b0ae8562 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,3 +42,4 @@ StyleCop.Cache
 UpgradeLog.htm
 .idea
 *.svclog
+mono_crash.*.json
diff --git a/src/Components/Server/test/ProtectedBrowserStorageTest.cs b/src/Components/Server/test/ProtectedBrowserStorageTest.cs
index 299e6861f971cb96dc4ab709813e5e055d33bfd8..1da3117c89c6c9a3123737d80b41b4edf3837074 100644
--- a/src/Components/Server/test/ProtectedBrowserStorageTest.cs
+++ b/src/Components/Server/test/ProtectedBrowserStorageTest.cs
@@ -12,6 +12,8 @@ using System.Threading.Tasks;
 using Microsoft.AspNetCore.DataProtection;
 using Microsoft.AspNetCore.WebUtilities;
 using Microsoft.JSInterop;
+using Microsoft.JSInterop.Infrastructure;
+using Moq;
 using Xunit;
 
 namespace Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@@ -265,7 +267,7 @@ namespace Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
         {
             // Arrange
             var jsRuntime = new TestJSRuntime();
-            jsRuntime.NextInvocationResult = new ValueTask<object>((object)null);
+            jsRuntime.NextInvocationResult = new ValueTask<IJSVoidResult>(Mock.Of<IJSVoidResult>());
             var dataProtectionProvider = new TestDataProtectionProvider();
             var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);
 
diff --git a/src/Components/Web.JS/src/Boot.WebAssembly.ts b/src/Components/Web.JS/src/Boot.WebAssembly.ts
index 76e103a1f12d36d70b03fbc04d199db7e99c971c..a25e719025fb5060ac3ca551c453d1a0aeef1421 100644
--- a/src/Components/Web.JS/src/Boot.WebAssembly.ts
+++ b/src/Components/Web.JS/src/Boot.WebAssembly.ts
@@ -163,6 +163,8 @@ function invokeJSFromDotNet(callInfo: Pointer, arg0: any, arg1: any, arg2: any):
         const streamReference = DotNet.createJSStreamReference(result);
         const resultJson = JSON.stringify(streamReference);
         return BINDING.js_string_to_mono_string(resultJson);
+      case DotNet.JSCallResultType.JSVoidResult:
+        return null;
       default:
         throw new Error(`Invalid JS call result type '${resultType}'.`);
     }
diff --git a/src/Components/WebAssembly/JSInterop/src/WebAssemblyJSRuntime.cs b/src/Components/WebAssembly/JSInterop/src/WebAssemblyJSRuntime.cs
index 53a6cb3947103d1c6263fc51c5b2eea0b4fadfb3..a91c184a28e0595cfee5db4376b77e70c5705e3e 100644
--- a/src/Components/WebAssembly/JSInterop/src/WebAssemblyJSRuntime.cs
+++ b/src/Components/WebAssembly/JSInterop/src/WebAssemblyJSRuntime.cs
@@ -91,6 +91,7 @@ namespace Microsoft.JSInterop.WebAssembly
             switch (resultType)
             {
                 case JSCallResultType.Default:
+                case JSCallResultType.JSVoidResult:
                     var result = InternalCalls.InvokeJS<T0, T1, T2, TResult>(out exception, ref callInfo, arg0, arg1, arg2);
                     return exception != null
                         ? throw new JSException(exception)
diff --git a/src/Components/test/E2ETest/Tests/InteropTest.cs b/src/Components/test/E2ETest/Tests/InteropTest.cs
index e3e8c46b18df39be3ec921e6c80de31a2b58c410..b3afb5e4d9e8dea1f69bf940d4475b901ec9b041 100644
--- a/src/Components/test/E2ETest/Tests/InteropTest.cs
+++ b/src/Components/test/E2ETest/Tests/InteropTest.cs
@@ -92,6 +92,8 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
                 ["asyncGenericInstanceMethod"] = @"""Updated value 1""",
                 ["requestDotNetStreamReferenceAsync"] = @"""Success""",
                 ["requestDotNetStreamWrapperReferenceAsync"] = @"""Success""",
+                ["invokeVoidAsyncReturnsWithoutSerializing"] = "Success",
+                ["invokeVoidAsyncReturnsWithoutSerializingInJSObjectReference"] = "Success",
             };
 
             var expectedSyncValues = new Dictionary<string, string>
diff --git a/src/Components/test/testassets/BasicTestApp/InteropComponent.razor b/src/Components/test/testassets/BasicTestApp/InteropComponent.razor
index 49671da348ec0d994b038de7257282801d9a2e22..bc0fe50657b7c37addfc319c34a3eae1efc4b03e 100644
--- a/src/Components/test/testassets/BasicTestApp/InteropComponent.razor
+++ b/src/Components/test/testassets/BasicTestApp/InteropComponent.razor
@@ -138,12 +138,36 @@
             ReturnValues["returnPrimitive"] = ((IJSInProcessRuntime)JSRuntime).Invoke<int>("returnPrimitive").ToString();
             ReturnValues["returnArray"] = string.Join(",", ((IJSInProcessRuntime)JSRuntime).Invoke<Segment[]>("returnArray").Select(x => x.Source).ToArray());
         }
+        
+        try
+        {
+            // Triger a non-serializable WindowProxy (https://developer.mozilla.org/en-US/docs/Web/API/Window)
+            // InvokeVoidAsync shouldn't serialize return values, and thus there shouldn't be any exception thrown. 
+            await JSRuntime.InvokeVoidAsync("eval", "window");
+            ReturnValues["invokeVoidAsyncReturnsWithoutSerializing"] = "Success";
+        }
+        catch (Exception ex)
+        {
+            ReturnValues["invokeVoidAsyncReturnsWithoutSerializing"] = $"Failure: {ex.Message}";
+        }
 
         var jsObjectReference = await JSRuntime.InvokeAsync<IJSObjectReference>("returnJSObjectReference");
         ReturnValues["jsObjectReference.identity"] = await jsObjectReference.InvokeAsync<string>("identity", "Invoked from JSObjectReference");
         ReturnValues["jsObjectReference.nested.add"] = (await jsObjectReference.InvokeAsync<int>("nested.add", 2, 3)).ToString();
         ReturnValues["addViaJSObjectReference"] = (await JSRuntime.InvokeAsync<int>("addViaJSObjectReference", jsObjectReference, 2, 3)).ToString();
 
+        try
+        {
+            // Fetch a non-serializable Window (https://developer.mozilla.org/en-US/docs/Web/API/Window)
+            // InvokeVoidAsync shouldn't serialize return values, and thus there shouldn't be any exception thrown. 
+            await jsObjectReference.InvokeVoidAsync("getWindow");
+            ReturnValues["invokeVoidAsyncReturnsWithoutSerializingInJSObjectReference"] = "Success";
+        }
+        catch (Exception ex)
+        {
+            ReturnValues["invokeVoidAsyncReturnsWithoutSerializingInJSObjectReference"] = $"Failure: {ex.Message}";
+        }
+
         try
         {
             await jsObjectReference.InvokeAsync<object>("nonFunction");
@@ -201,7 +225,7 @@
 
         var dotNetStreamReferenceWrapper = DotNetStreamReferenceInterop.GetDotNetStreamWrapperReference();
         ReturnValues["dotNetToJSReceiveDotNetStreamWrapperReferenceAsync"] = await JSRuntime.InvokeAsync<string>("jsInteropTests.receiveDotNetStreamWrapperReference", dotNetStreamReferenceWrapper);
-
+        
         Invocations = invocations;
         DoneWithInterop = true;
     }
diff --git a/src/Components/test/testassets/BasicTestApp/wwwroot/js/jsinteroptests.js b/src/Components/test/testassets/BasicTestApp/wwwroot/js/jsinteroptests.js
index af90a946230ea17a48399994286ecb8c4fd0f4f0..4bdc147ee0b6d93ca4e665b1c020f31dab572580 100644
--- a/src/Components/test/testassets/BasicTestApp/wwwroot/js/jsinteroptests.js
+++ b/src/Components/test/testassets/BasicTestApp/wwwroot/js/jsinteroptests.js
@@ -324,6 +324,9 @@ function returnJSObjectReference() {
     identity: function (value) {
       return value;
     },
+    getWindow: function() {
+      return window;
+    },
     nonFunction: 123,
     nested: {
       add: function (a, b) {
diff --git a/src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts b/src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts
index e51f45db2f86df4f06ef88c66166fc829837903b..22c55ca6646db425ca2394fd877d7db15a3f8c81 100644
--- a/src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts
+++ b/src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts
@@ -280,6 +280,7 @@ export module DotNet {
     Default = 0,
     JSObjectReference = 1,
     JSStreamReference = 2,
+    JSVoidResult = 3,
   }
 
   /**
@@ -566,6 +567,8 @@ export module DotNet {
         return createJSObjectReference(returnValue);
       case JSCallResultType.JSStreamReference:
         return createJSStreamReference(returnValue);
+      case JSCallResultType.JSVoidResult:
+        return null;
       default:
         throw new Error(`Invalid JS call result type '${resultType}'.`);
     }
diff --git a/src/JSInterop/Microsoft.JSInterop/src/Infrastructure/IJSVoidResult.cs b/src/JSInterop/Microsoft.JSInterop/src/Infrastructure/IJSVoidResult.cs
new file mode 100644
index 0000000000000000000000000000000000000000..5b679b3160af2235ff08f0624a4df48f614392a4
--- /dev/null
+++ b/src/JSInterop/Microsoft.JSInterop/src/Infrastructure/IJSVoidResult.cs
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+using System.ComponentModel;
+
+namespace Microsoft.JSInterop.Infrastructure
+{
+    /// <summary>
+    /// Represents a void result from a JavaScript call.
+    /// This property is public to support cross-assembly accessibility for WebAssembly and should not be used by user code.
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public interface IJSVoidResult
+    {
+    }
+}
diff --git a/src/JSInterop/Microsoft.JSInterop/src/JSCallResultType.cs b/src/JSInterop/Microsoft.JSInterop/src/JSCallResultType.cs
index b92dd14848c5b5e4117b3c39de565a434fce0f7e..28f08586dbd38296fcdfcae518fabd49b8d9fbcd 100644
--- a/src/JSInterop/Microsoft.JSInterop/src/JSCallResultType.cs
+++ b/src/JSInterop/Microsoft.JSInterop/src/JSCallResultType.cs
@@ -22,5 +22,10 @@ namespace Microsoft.JSInterop
         /// Indicates that the returned value is to be treated as a JS data reference.
         /// </summary>
         JSStreamReference = 2,
+
+        /// <summary>
+        /// Indicates a void result type.
+        /// </summary>
+        JSVoidResult = 3,
     }
 }
diff --git a/src/JSInterop/Microsoft.JSInterop/src/JSObjectReferenceExtensions.cs b/src/JSInterop/Microsoft.JSInterop/src/JSObjectReferenceExtensions.cs
index 3c83f7694fb7a3586c7b1326a74e3fef8455efc5..c1067f544a1776cef78e2a82a3d2c9a143fb971d 100644
--- a/src/JSInterop/Microsoft.JSInterop/src/JSObjectReferenceExtensions.cs
+++ b/src/JSInterop/Microsoft.JSInterop/src/JSObjectReferenceExtensions.cs
@@ -5,6 +5,7 @@ using System;
 using System.Diagnostics.CodeAnalysis;
 using System.Threading;
 using System.Threading.Tasks;
+using Microsoft.JSInterop.Infrastructure;
 using static Microsoft.AspNetCore.Internal.LinkerFlags;
 
 namespace Microsoft.JSInterop
@@ -28,7 +29,7 @@ namespace Microsoft.JSInterop
                 throw new ArgumentNullException(nameof(jsObjectReference));
             }
 
-            await jsObjectReference.InvokeAsync<object>(identifier, args);
+            await jsObjectReference.InvokeAsync<IJSVoidResult>(identifier, args);
         }
 
         /// <summary>
@@ -93,7 +94,7 @@ namespace Microsoft.JSInterop
                 throw new ArgumentNullException(nameof(jsObjectReference));
             }
 
-            await jsObjectReference.InvokeAsync<object>(identifier, cancellationToken, args);
+            await jsObjectReference.InvokeAsync<IJSVoidResult>(identifier, cancellationToken, args);
         }
 
         /// <summary>
@@ -135,7 +136,7 @@ namespace Microsoft.JSInterop
             using var cancellationTokenSource = timeout == Timeout.InfiniteTimeSpan ? null : new CancellationTokenSource(timeout);
             var cancellationToken = cancellationTokenSource?.Token ?? CancellationToken.None;
 
-            await jsObjectReference.InvokeAsync<object>(identifier, cancellationToken, args);
+            await jsObjectReference.InvokeAsync<IJSVoidResult>(identifier, cancellationToken, args);
         }
     }
 }
diff --git a/src/JSInterop/Microsoft.JSInterop/src/JSRuntimeExtensions.cs b/src/JSInterop/Microsoft.JSInterop/src/JSRuntimeExtensions.cs
index 5b904931981e9eb0716960a6bdd531f4e41048f6..c687c1cc983b7d210a101180bbfa14677c37b76d 100644
--- a/src/JSInterop/Microsoft.JSInterop/src/JSRuntimeExtensions.cs
+++ b/src/JSInterop/Microsoft.JSInterop/src/JSRuntimeExtensions.cs
@@ -5,6 +5,7 @@ using System;
 using System.Diagnostics.CodeAnalysis;
 using System.Threading;
 using System.Threading.Tasks;
+using Microsoft.JSInterop.Infrastructure;
 using static Microsoft.AspNetCore.Internal.LinkerFlags;
 
 namespace Microsoft.JSInterop
@@ -28,7 +29,7 @@ namespace Microsoft.JSInterop
                 throw new ArgumentNullException(nameof(jsRuntime));
             }
 
-            await jsRuntime.InvokeAsync<object>(identifier, args);
+            await jsRuntime.InvokeAsync<IJSVoidResult>(identifier, args);
         }
 
         /// <summary>
@@ -93,7 +94,7 @@ namespace Microsoft.JSInterop
                 throw new ArgumentNullException(nameof(jsRuntime));
             }
 
-            await jsRuntime.InvokeAsync<object>(identifier, cancellationToken, args);
+            await jsRuntime.InvokeAsync<IJSVoidResult>(identifier, cancellationToken, args);
         }
 
         /// <summary>
@@ -135,7 +136,7 @@ namespace Microsoft.JSInterop
             using var cancellationTokenSource = timeout == Timeout.InfiniteTimeSpan ? null : new CancellationTokenSource(timeout);
             var cancellationToken = cancellationTokenSource?.Token ?? CancellationToken.None;
 
-            await jsRuntime.InvokeAsync<object>(identifier, cancellationToken, args);
+            await jsRuntime.InvokeAsync<IJSVoidResult>(identifier, cancellationToken, args);
         }
     }
 }
diff --git a/src/JSInterop/Microsoft.JSInterop/src/PublicAPI.Unshipped.txt b/src/JSInterop/Microsoft.JSInterop/src/PublicAPI.Unshipped.txt
index cca17c3ed56306ea419d480c89f06c80cb935728..78398df5fdf0acdbfc94671877e3868624918cae 100644
--- a/src/JSInterop/Microsoft.JSInterop/src/PublicAPI.Unshipped.txt
+++ b/src/JSInterop/Microsoft.JSInterop/src/PublicAPI.Unshipped.txt
@@ -11,7 +11,9 @@ Microsoft.JSInterop.DotNetStreamReference.DotNetStreamReference(System.IO.Stream
 Microsoft.JSInterop.DotNetStreamReference.LeaveOpen.get -> bool
 Microsoft.JSInterop.DotNetStreamReference.Stream.get -> System.IO.Stream!
 Microsoft.JSInterop.Infrastructure.DotNetInvocationResult.ResultJson.get -> string?
+Microsoft.JSInterop.Infrastructure.IJSVoidResult
 Microsoft.JSInterop.JSCallResultType.JSStreamReference = 2 -> Microsoft.JSInterop.JSCallResultType
+Microsoft.JSInterop.JSCallResultType.JSVoidResult = 3 -> Microsoft.JSInterop.JSCallResultType
 Microsoft.JSInterop.JSRuntime.Dispose() -> void
 static Microsoft.JSInterop.Implementation.JSObjectReferenceJsonWorker.ReadJSObjectReferenceIdentifier(ref System.Text.Json.Utf8JsonReader reader) -> long
 static Microsoft.JSInterop.Implementation.JSObjectReferenceJsonWorker.WriteJSObjectReference(System.Text.Json.Utf8JsonWriter! writer, Microsoft.JSInterop.Implementation.JSObjectReference! objectReference) -> void
diff --git a/src/JSInterop/Microsoft.JSInterop/test/JSRuntimeExtensionsTest.cs b/src/JSInterop/Microsoft.JSInterop/test/JSRuntimeExtensionsTest.cs
index b8061a2c3caa2212b592f837a9971a247e86e7ab..2ca3961be301cb9bb777103be295366c312381ec 100644
--- a/src/JSInterop/Microsoft.JSInterop/test/JSRuntimeExtensionsTest.cs
+++ b/src/JSInterop/Microsoft.JSInterop/test/JSRuntimeExtensionsTest.cs
@@ -4,6 +4,7 @@
 using System;
 using System.Threading;
 using System.Threading.Tasks;
+using Microsoft.JSInterop.Infrastructure;
 using Moq;
 using Xunit;
 
@@ -65,7 +66,7 @@ namespace Microsoft.JSInterop
             var method = "someMethod";
             var args = new[] { "a", "b" };
             var jsRuntime = new Mock<IJSRuntime>(MockBehavior.Strict);
-            jsRuntime.Setup(s => s.InvokeAsync<object>(method, args)).Returns(new ValueTask<object>(new object()));
+            jsRuntime.Setup(s => s.InvokeAsync<IJSVoidResult>(method, args)).Returns(new ValueTask<IJSVoidResult>(Mock.Of<IJSVoidResult>()));
 
             // Act
             await jsRuntime.Object.InvokeVoidAsync(method, args);
@@ -80,7 +81,7 @@ namespace Microsoft.JSInterop
             var method = "someMethod";
             var args = new[] { "a", "b" };
             var jsRuntime = new Mock<IJSRuntime>(MockBehavior.Strict);
-            jsRuntime.Setup(s => s.InvokeAsync<object>(method, It.IsAny<CancellationToken>(), args)).Returns(new ValueTask<object>(new object()));
+            jsRuntime.Setup(s => s.InvokeAsync<IJSVoidResult>(method, It.IsAny<CancellationToken>(), args)).Returns(new ValueTask<IJSVoidResult>(Mock.Of<IJSVoidResult>()));
 
             // Act
             await jsRuntime.Object.InvokeVoidAsync(method, new CancellationToken(), args);
@@ -142,14 +143,14 @@ namespace Microsoft.JSInterop
             var method = "someMethod";
             var args = new[] { "a", "b" };
             var jsRuntime = new Mock<IJSRuntime>(MockBehavior.Strict);
-            jsRuntime.Setup(s => s.InvokeAsync<object>(method, It.IsAny<CancellationToken>(), args))
+            jsRuntime.Setup(s => s.InvokeAsync<IJSVoidResult>(method, It.IsAny<CancellationToken>(), args))
                 .Callback<string, CancellationToken, object[]>((method, cts, args) =>
                 {
                     // There isn't a very good way to test when the cts will cancel. We'll just verify that
                     // it'll get cancelled eventually.
                     Assert.True(cts.CanBeCanceled);
                 })
-                .Returns(new ValueTask<object>(new object()));
+                .Returns(new ValueTask<IJSVoidResult>(Mock.Of<IJSVoidResult>()));
 
             // Act
             await jsRuntime.Object.InvokeVoidAsync(method, TimeSpan.FromMinutes(5), args);
@@ -164,13 +165,13 @@ namespace Microsoft.JSInterop
             var method = "someMethod";
             var args = new[] { "a", "b" };
             var jsRuntime = new Mock<IJSRuntime>(MockBehavior.Strict);
-            jsRuntime.Setup(s => s.InvokeAsync<object>(method, It.IsAny<CancellationToken>(), args))
+            jsRuntime.Setup(s => s.InvokeAsync<IJSVoidResult>(method, It.IsAny<CancellationToken>(), args))
                 .Callback<string, CancellationToken, object[]>((method, cts, args) =>
                 {
                     Assert.False(cts.CanBeCanceled);
                     Assert.True(cts == CancellationToken.None);
                 })
-                .Returns(new ValueTask<object>(new object()));
+                .Returns(new ValueTask<IJSVoidResult>(Mock.Of<IJSVoidResult>()));
 
             // Act
             await jsRuntime.Object.InvokeVoidAsync(method, Timeout.InfiniteTimeSpan, args);
diff --git a/src/Shared/JSInterop/JSCallResultTypeHelper.cs b/src/Shared/JSInterop/JSCallResultTypeHelper.cs
index a61f54397109dbc40710bd85db321c4176d24c8f..049a9bd9ed8f717e0f60e319efcc8cb4f1fc2987 100644
--- a/src/Shared/JSInterop/JSCallResultTypeHelper.cs
+++ b/src/Shared/JSInterop/JSCallResultTypeHelper.cs
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Reflection;
+using Microsoft.JSInterop.Infrastructure;
 
 namespace Microsoft.JSInterop
 {
@@ -12,21 +13,25 @@ namespace Microsoft.JSInterop
 
         public static JSCallResultType FromGeneric<TResult>()
         {
-            if (typeof(TResult).Assembly == _currentAssembly
-                && (typeof(TResult) == typeof(IJSObjectReference)
-                || typeof(TResult) == typeof(IJSInProcessObjectReference)
-                || typeof(TResult) == typeof(IJSUnmarshalledObjectReference)))
+            if (typeof(TResult).Assembly == _currentAssembly)
             {
-                return JSCallResultType.JSObjectReference;
-            }
-            else if (typeof(TResult).Assembly == _currentAssembly && typeof(TResult) == typeof(IJSStreamReference))
-            {
-                return JSCallResultType.JSStreamReference;
-            }
-            else
-            {
-                return JSCallResultType.Default;
+                if (typeof(TResult) == typeof(IJSObjectReference) ||
+                    typeof(TResult) == typeof(IJSInProcessObjectReference) ||
+                    typeof(TResult) == typeof(IJSUnmarshalledObjectReference))
+                {
+                    return JSCallResultType.JSObjectReference;
+                }
+                else if (typeof(TResult) == typeof(IJSStreamReference))
+                {
+                    return JSCallResultType.JSStreamReference;
+                }
+                else if (typeof(TResult) == typeof(IJSVoidResult))
+                {
+                    return JSCallResultType.JSVoidResult;
+                }
             }
+
+            return JSCallResultType.Default;
         }
     }
 }