diff --git a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs
index 8462c8399477f..e170fcc5a09cd 100644
--- a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs
+++ b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs
@@ -551,13 +551,9 @@ public void NumberToDouble_Valid(string jsonValue, double expectedParsedValue)
         }
 
         [Test]
-        // Skip these test cases in .NET 5 because floating point parsing supports bigger values.
-        // These big values won't throw an error in the test.
-#if !NETCOREAPP3_1_OR_GREATER
         [TestCase("1.7977e308")]
         [TestCase("-1.7977e308")]
         [TestCase("1e309")]
-#endif
         [TestCase("1,0")]
         [TestCase("1.0.0")]
         [TestCase("+1")]
diff --git a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
index 7cc5c6bcfb518..df43effd4ff0f 100644
--- a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
+++ b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs
@@ -199,12 +199,8 @@ public void NumberValue(string json, double expectedValue)
         [TestCase("1e-")]
         [TestCase("--")]
         [TestCase("--1")]
-        // Skip these test cases in .NET 5 because floating point parsing supports bigger values.
-        // These big values won't throw an error in the test.
-#if !NETCOREAPP3_1_OR_GREATER
         [TestCase("-1.7977e308")]
         [TestCase("1.7977e308")]
-#endif
         public void InvalidNumberValue(string json)
         {
             AssertThrowsAfter(json);
diff --git a/csharp/src/Google.Protobuf/JsonTokenizer.cs b/csharp/src/Google.Protobuf/JsonTokenizer.cs
index 4725e7cc51197..13a12c05dd44c 100644
--- a/csharp/src/Google.Protobuf/JsonTokenizer.cs
+++ b/csharp/src/Google.Protobuf/JsonTokenizer.cs
@@ -471,9 +471,18 @@ private double ReadNumber(char initialCharacter)
                 // TODO: What exception should we throw if the value can't be represented as a double?
                 try
                 {
-                    return double.Parse(builder.ToString(),
+                    double result = double.Parse(builder.ToString(),
                         NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent,
                         CultureInfo.InvariantCulture);
+
+                    // .NET Core 3.0 and later returns infinity if the number is too large or small to be represented.
+                    // For compatibility with other Protobuf implementations the tokenizer should still throw.
+                    if (double.IsInfinity(result))
+                    {
+                        throw reader.CreateException("Numeric value out of range: " + builder);
+                    }
+
+                    return result;
                 }
                 catch (OverflowException)
                 {