diff --git a/CSharpDriver.Bson.slnf b/CSharpDriver.Bson.slnf
deleted file mode 100644
index 56265b22f69..00000000000
--- a/CSharpDriver.Bson.slnf
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "solution": {
-    "path": "CSharpDriver.sln",
-    "projects": [
-      "src\\MongoDB.Bson\\MongoDB.Bson.csproj",
-      "tests\\MongoDB.Bson.TestHelpers\\MongoDB.Bson.TestHelpers.csproj",
-      "tests\\MongoDB.Bson.Tests\\MongoDB.Bson.Tests.csproj"
-    ]
-  }
-}
diff --git a/CSharpDriver.Driver.Core.slnf b/CSharpDriver.Driver.Core.slnf
deleted file mode 100644
index 8ad13e9d183..00000000000
--- a/CSharpDriver.Driver.Core.slnf
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "solution": {
-    "path": "CSharpDriver.sln",
-    "projects": [
-      "src\\MongoDB.Bson\\MongoDB.Bson.csproj",
-      "src\\MongoDB.Driver.Core\\MongoDB.Driver.Core.csproj",
-      "tests\\MongoDB.Bson.TestHelpers\\MongoDB.Bson.TestHelpers.csproj",
-      "tests\\MongoDB.Driver.Core.TestHelpers\\MongoDB.Driver.Core.TestHelpers.csproj",
-      "tests\\MongoDB.Driver.Core.Tests\\MongoDB.Driver.Core.Tests.csproj"
-    ]
-  }
-}
diff --git a/CSharpDriver.Driver.slnf b/CSharpDriver.Driver.slnf
deleted file mode 100644
index 59d218d11f0..00000000000
--- a/CSharpDriver.Driver.slnf
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "solution": {
-    "path": "CSharpDriver.sln",
-    "projects": [
-      "src\\MongoDB.Bson\\MongoDB.Bson.csproj",
-      "src\\MongoDB.Driver.Core\\MongoDB.Driver.Core.csproj",
-      "src\\MongoDB.Driver.GridFS\\MongoDB.Driver.GridFS.csproj",
-      "src\\MongoDB.Driver\\MongoDB.Driver.csproj",
-      "tests\\MongoDB.Bson.TestHelpers\\MongoDB.Bson.TestHelpers.csproj",
-      "tests\\MongoDB.Driver.Core.TestHelpers\\MongoDB.Driver.Core.TestHelpers.csproj",
-      "tests\\MongoDB.Driver.TestHelpers\\MongoDB.Driver.TestHelpers.csproj",
-      "tests\\MongoDB.Driver.Tests\\MongoDB.Driver.Tests.csproj"
-    ]
-  }
-}
diff --git a/README.md b/README.md
index 16be4f4970e..d3f37f5d2bf 100644
--- a/README.md
+++ b/README.md
@@ -76,96 +76,4 @@ Contributing
 
 Please see our [guidelines](CONTRIBUTING.md) for contributing to the driver.
 
-### Maintainers:
-* Boris Dogadov             boris.dogadov@mongodb.com
-* James Kovacs              james.kovacs@mongodb.com
-* Oleksandr Poliakov        oleksandr.poliakov@mongodb.com
-* Robert Stam               robert@mongodb.com
-
-### Contributors:
-* Alexander Aramov          https://github.com/alex687
-* Bar Arnon                 https://github.com/I3arnon
-* Wan Bachtiar              https://github.com/sindbach
-* Mark Benvenuto            https://github.com/markbenvenuto
-* Brian Buvinghausen        https://github.com/buvinghausen
-* Bit Diffusion Limited     code@bitdiff.com
-* Jimmy Bogard              https://github.com/jbogard
-* Ross Buggins              https://github.com/rbugginsvia
-* Nima Boscarino            https://github.com/NimaBoscarino
-* Oscar Bralo               https://github.com/Oscarbralo
-* Alex Brown                https://github.com/alexjamesbrown
-* Ethan Celletti            https://github.com/Gekctek
-* Chris Cho                 https://github.com/ccho-mongodb
-* Adam Avery Cole           https://github.com/adamaverycole
-* Nate Contino              https://github.com/nathan-contino-mongo
-* Alex Dawes                https://github.com/alexdawes
-* Justin Dearing            zippy1981@gmail.com
-* Dan DeBilt                dan.debilt@gmail.com
-* Teun Duynstee             teun@duynstee.com
-* Einar Egilsson            https://github.com/einaregilsson
-* Ken Egozi                 mail@kenegozi.com
-* Alexander Endris          https://github.com/AlexEndris
-* Daniel Goldman            daniel@stackwave.com
-* David Golub               https://github.com/dgolub
-* Simon Green               simon@captaincodeman.com
-* Bouke Haarsma             https://github.com/Bouke
-* James Hadwen              james.hadwen@sociustec.com
-* Nuri Halperin             https://github.com/nurih
-* Daniel Hegener            daniel.hegener@fisglobal.com
-* Nikola Irinchev           https://github.com/nirinchev
-* Jacob Jewell              jacobjewell@eflexsystems.com
-* Vincent Kam               https://github.com/vincentkam
-* Danny Kendrick            https://github.com/dkendrick
-* Ruslan Khasanbaev         https://github.com/flaksirus
-* Konstantin Khitrykh       https://github.com/KonH
-* Brian Knight              brianknight10@gmail.com
-* John Knoop                https://github.com/johnknoop
-* Andrey Kondratyev         https://github.com/byTimo
-* Anatoly Koperin           https://github.com/ExM
-* Nik Kolev                 nkolev@gmail.com
-* Oleg Kosmakov             https://github.com/kosmakoff
-* Maksim Krautsou           https://github.com/MaKCbIMKo
-* Richard Kreuter           richard@10gen.com
-* Daniel Lee                https://github.com/dlee148
-* Ming Yau Lee              https://github.com/mingyaulee
-* Kevin Lewis               kevin.l.lewis@gmail.com
-* Dow Liu                   redforks@gmail.com
-* Chuck Lu                  https://github.com/chucklu
-* Alex Lyman                mail.alex.lyman@gmail.com
-* Tomasz Masternak          https://github.com/tmasternak
-* Mikalai Mazurenka         mikalai.mazurenka@mongodb.com
-* John Murphy               https://github.com/jsmurphy
-* Alexander Nagy            optimiz3@gmail.com
-* Sridhar Nanjundeswaran    https://github.com/sridharn
-* Nathan                    https://github.com/terakilobyte
-* Adelin Owona              https://github.com/adelinowona
-* Rachelle Palmer           https://github.com/techbelle
-* Rich Quackenbush          rich.quackenbush@captiveaire.com
-* Carl Reinke               https://github.com/mindless2112
-* Rodrigo Reis              https://github.com/rodrigoreis
-* Gian Maria Ricci          https://github.com/alkampfergit
-* Andrew Rondeau            github@andrewrondeau.com
-* Ed Rooth                  edward.rooth@wallstreetjapan.com
-* Katie Sadoff              https://github.com/ksadoff
-* Manas Sahu                https://github.com/Zangetsu112
-* Sam558                    https://github.com/Sam558
-* Vladimir Setyaev          setyaev_v@pgstudio.io
-* Sergey Shushlyapin        https://github.com/sergeyshushlyapin
-* Alexey Skalozub           pieceofsummer@gmail.com
-* Kevin Smith               https://github.com/kevbite
-* Pete Smith                roysvork@gmail.com
-* Matteo Spreafico          https://github.com/MatteoSp
-* staywellandy              https://github.com/staywellandy
-* Vyacheslav Stroy          https://github.com/kreig
-* Jake Sta. Teresa          https://github.com/JakeStaTeresa
-* Testo                     test1@doramail.com
-* TimTim                    https://github.com/wegylexy
-* Craig Wilson              https://github.com/craiggwilson
-* Zhmayev Yaroslav          https://github.com/salaros
-* Aristarkh Zagorodnikov    https://github.com/onyxmaster
-* Samir Boulema             https://github.com/sboulema
-* Dmitry Lukyanov           https://github.com/DmitryLukyanov
-* Andrea Balducci           https://github.com/andreabalducci
-* Sergei Lipin              https://github.com/prchaoz
-
-If you have contributed and we have neglected to add you to this list please contact one of the maintainers to be added to the list (with apologies).
+Thank you to [everyone](https://github.com/mongodb/mongo-csharp-driver/graphs/contributors) who has contributed to this project.
diff --git a/Release Notes/Release Notes v2.25.0.md b/Release Notes/Release Notes v2.25.0.md
index ddc3b28ef61..d172ba58fe4 100644
--- a/Release Notes/Release Notes v2.25.0.md	
+++ b/Release Notes/Release Notes v2.25.0.md	
@@ -17,4 +17,4 @@ The main new features in 2.25.0 include:
 
 The full list of issues resolved in this release is available at [CSHARP JIRA project](https://jira.mongodb.org/issues/?jql=project%20%3D%20CSHARP%20AND%20fixVersion%20%3D%202.25.0%20ORDER%20BY%20key%20ASC).
 
-Documentation on the .NET driver can be found [here](https://www.mongodb.com/docs/drivers/csharp/v2.25.0}/).
+Documentation on the .NET driver can be found [here](https://www.mongodb.com/docs/drivers/csharp/v2.25/).
diff --git a/Release Notes/Release Notes v2.26.0.md b/Release Notes/Release Notes v2.26.0.md
index c48d4d466c6..469b6874846 100644
--- a/Release Notes/Release Notes v2.26.0.md	
+++ b/Release Notes/Release Notes v2.26.0.md	
@@ -16,4 +16,4 @@ The main new features in 2.26.0 include:
 
 The full list of issues resolved in this release is available at [CSHARP JIRA project](https://jira.mongodb.org/issues/?jql=project%20%3D%20CSHARP%20AND%20fixVersion%20%3D%202.26.0%20ORDER%20BY%20key%20ASC).
 
-Documentation on the .NET driver can be found [here](https://www.mongodb.com/docs/drivers/csharp/v2.26.0}/).
+Documentation on the .NET driver can be found [here](https://www.mongodb.com/docs/drivers/csharp/v2.26/).
diff --git a/Release Notes/Release Notes v2.28.0.md b/Release Notes/Release Notes v2.28.0.md
new file mode 100644
index 00000000000..635709c65e3
--- /dev/null
+++ b/Release Notes/Release Notes v2.28.0.md	
@@ -0,0 +1,22 @@
+# .NET Driver Version 2.28.0 Release Notes
+
+This is the general availability release for the 2.28.0 version of the driver.
+
+NOTICE: MongoDB 3.6 reached end-of-life in April 2021. The .NET/C# Driver will be removing support for MongoDB 3.6 in an upcoming release.
+
+The main new features in 2.28.0 include:
+
++ Provide Strong-Named Assemblies - [CSHARP-1276](https://jira.mongodb.org/browse/CSHARP-1276)
++ Support additional numeric conversions involving Nullable<T> - [CSHARP-5180](https://jira.mongodb.org/browse/CSHARP-5180)
++ CSFLE/QE KMIP support "delegated" protocol - [CSHARP-4941](https://jira.mongodb.org/browse/CSHARP-4941)
+
+## Bug fixes:
++ Verify that operands to numeric operators in LINQ expressions are represented as numbers on the server - [CSHARP-4985](https://jira.mongodb.org/browse/CSHARP-4985)
++ IReadOnlyDictionary indexer access fails to translate in v3 - [CSHARP-5171](https://jira.mongodb.org/browse/CSHARP-5171)
++ Projection Expressions Fail to Deserialize Data Correctly - [CSHARP-5162](https://jira.mongodb.org/browse/CSHARP-5162)
++ Enum conversion within IQueryable fails with Expression not supported exception - [CSHARP-5043](https://jira.mongodb.org/browse/CSHARP-5043)
++ IMongoCollection.AsQueryable().Select() fails for array type (regression) - [CSHARP-4957](https://jira.mongodb.org/browse/CSHARP-4957)
+
+The full list of issues resolved in this release is available at [CSHARP JIRA project](https://jira.mongodb.org/issues/?jql=project%20%3D%20CSHARP%20AND%20fixVersion%20%3D%202.28.0%20ORDER%20BY%20key%20ASC).
+
+Documentation on the .NET driver can be found [here](https://www.mongodb.com/docs/drivers/csharp/v2.28/).
diff --git a/packageIcon.png b/packageIcon.png
index d5dfcc632b4..e55bc6a1c91 100644
Binary files a/packageIcon.png and b/packageIcon.png differ
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 59caaf35767..f1b34632505 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -16,6 +16,8 @@
     <Copyright>Copyright © 2010-present MongoDB Inc.</Copyright>
     <Authors>Etherna Sagl</Authors>
     <PackageIcon>packageIcon.png</PackageIcon>
+    <PackageReadmeFile>README.md</PackageReadmeFile>
+    <PackageReleaseNotes>https://github.com/mongodb/mongo-csharp-driver/releases/tag/v$(Version)</PackageReleaseNotes>
     <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
     <PackageProjectUrl>https://www.mongodb.com/docs/drivers/csharp/</PackageProjectUrl>
     <PackageTags>mongodb;mongo;nosql</PackageTags>
@@ -50,5 +52,6 @@
 
   <ItemGroup>
     <None Include="..\..\packageIcon.png" Pack="true" PackagePath="" />
+    <None Include="..\..\README.md" Pack="true" PackagePath=""/>
   </ItemGroup>
 </Project>
diff --git a/src/MongoDB.Bson/Properties/AssemblyInfo.cs b/src/MongoDB.Bson/Properties/AssemblyInfo.cs
index 37a86d96563..2e340e738cb 100644
--- a/src/MongoDB.Bson/Properties/AssemblyInfo.cs
+++ b/src/MongoDB.Bson/Properties/AssemblyInfo.cs
@@ -26,4 +26,5 @@
 // as Xamarin.iOS/Xamarin.Mac.
 [assembly: Preserve(AllMembers = true)]
 
-[assembly: InternalsVisibleTo("MongoDB.Bson.Tests")]
+[assembly: InternalsVisibleTo("MongoDB.Bson.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")]
+[assembly: InternalsVisibleTo("MongoDB.Analyzer.MQLGenerator, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")]
diff --git a/src/MongoDB.Bson/Serialization/TypeNameDiscriminator.cs b/src/MongoDB.Bson/Serialization/TypeNameDiscriminator.cs
index 9455ece825d..5527778128f 100644
--- a/src/MongoDB.Bson/Serialization/TypeNameDiscriminator.cs
+++ b/src/MongoDB.Bson/Serialization/TypeNameDiscriminator.cs
@@ -145,7 +145,9 @@ public static string GetDiscriminator(Type type)
                 if (match.Success)
                 {
                     var publicKeyToken = match.Groups["token"].Value;
-                    if (publicKeyToken == "null")
+                    if (publicKeyToken == "null" ||
+                        // MongoDB's assemblies should use "type name, assembly name" discriminator format for backward compatibility
+                        (assembly.FullName.StartsWith("MongoDB") && publicKeyToken == "94992a530f44e321"))
                     {
                         var dllName = match.Groups["dll"].Value;
                         assemblyName = dllName;
diff --git a/src/MongoDB.Driver.Core/Core/Clusters/ServerSelectors/WritableServerSelector.cs b/src/MongoDB.Driver.Core/Core/Clusters/ServerSelectors/WritableServerSelector.cs
index c6cfef1e58c..6beba601631 100644
--- a/src/MongoDB.Driver.Core/Core/Clusters/ServerSelectors/WritableServerSelector.cs
+++ b/src/MongoDB.Driver.Core/Core/Clusters/ServerSelectors/WritableServerSelector.cs
@@ -98,7 +98,7 @@ public override string ToString()
 
         private bool CanUseSecondaries(ClusterDescription cluster, List<ServerDescription> servers)
         {
-            if (_mayUseSecondary?.ReadPreference == null || servers.Count == 0)
+            if (_mayUseSecondary?.ReadPreference == null)
             {
                 return false;
             }
@@ -107,6 +107,11 @@ private bool CanUseSecondaries(ClusterDescription cluster, List<ServerDescriptio
             {
                 case ClusterType.ReplicaSet:
                 case ClusterType.Sharded:
+                    if (servers.Count == 0)
+                    {
+                        return true;
+                    }
+
                     return servers.All(s => _mayUseSecondary.CanUseSecondary(s));
 
                 case ClusterType.LoadBalanced:
diff --git a/src/MongoDB.Driver.Core/Core/Servers/ServerMonitor.cs b/src/MongoDB.Driver.Core/Core/Servers/ServerMonitor.cs
index ecd92457783..35f876990a4 100644
--- a/src/MongoDB.Driver.Core/Core/Servers/ServerMonitor.cs
+++ b/src/MongoDB.Driver.Core/Core/Servers/ServerMonitor.cs
@@ -369,11 +369,8 @@ private void Heartbeat(CancellationToken cancellationToken)
                 ServerDescription newDescription;
                 if (heartbeatHelloResult != null)
                 {
-                    var averageRoundTripTime = _roundTripTimeMonitor.Average;
-                    var averageRoundTripTimeRounded = TimeSpan.FromMilliseconds(Math.Round(averageRoundTripTime.TotalMilliseconds));
-
                     newDescription = _baseDescription.With(
-                        averageRoundTripTime: averageRoundTripTimeRounded,
+                        averageRoundTripTime: _roundTripTimeMonitor.Average,
                         canonicalEndPoint: heartbeatHelloResult.Me,
                         electionId: heartbeatHelloResult.ElectionId,
                         helloOk: heartbeatHelloResult.HelloOk,
diff --git a/src/MongoDB.Driver.Core/Etherna.MongoDB.Driver.Core.csproj b/src/MongoDB.Driver.Core/Etherna.MongoDB.Driver.Core.csproj
index ea71cbecf12..c205b5f68db 100644
--- a/src/MongoDB.Driver.Core/Etherna.MongoDB.Driver.Core.csproj
+++ b/src/MongoDB.Driver.Core/Etherna.MongoDB.Driver.Core.csproj
@@ -28,7 +28,7 @@
     <PackageReference Include="AWSSDK.SecurityToken" Version="3.7.100.14" />
     <PackageReference Include="DnsClient" Version="1.6.1" />
     <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.0" />
-    <PackageReference Include="MongoDB.Libmongocrypt" Version="1.10.0" />
+    <PackageReference Include="MongoDB.Libmongocrypt" Version="1.11.0" />
     <PackageReference Include="SharpCompress" Version="0.30.1" />
     <PackageReference Include="Snappier" Version="1.0.0" />
     <PackageReference Include="ZstdSharp.Port" Version="0.7.3" />
diff --git a/src/MongoDB.Driver.Core/Properties/AssemblyInfo.cs b/src/MongoDB.Driver.Core/Properties/AssemblyInfo.cs
index 513e5e05683..04f0330d93e 100644
--- a/src/MongoDB.Driver.Core/Properties/AssemblyInfo.cs
+++ b/src/MongoDB.Driver.Core/Properties/AssemblyInfo.cs
@@ -28,10 +28,10 @@
 [assembly: InternalsVisibleTo("Etherna.MongoDB.Driver")]
 [assembly: InternalsVisibleTo("Etherna.MongoDB.Driver.TestHelpers")]
 [assembly: InternalsVisibleTo("Etherna.MongoDB.Driver.Legacy")]
-[assembly: InternalsVisibleTo("Etherna.MongoDB.Driver.Core.FunctionalTests")]
 [assembly: InternalsVisibleTo("Etherna.MongoDB.Driver.Core.TestHelpers")]
 [assembly: InternalsVisibleTo("Etherna.MongoDB.Driver.Core.Tests")]
 [assembly: InternalsVisibleTo("Etherna.MongoDB.Driver.Legacy.Tests")]
 [assembly: InternalsVisibleTo("Etherna.MongoDB.Driver.Legacy.TestHelpers")]
 [assembly: InternalsVisibleTo("Etherna.MongoDB.Driver.Tests")]
-[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
+[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
+[assembly: InternalsVisibleTo("MongoDB.Analyzer.MQLGenerator, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")]
diff --git a/src/MongoDB.Driver.GridFS/Properties/AssemblyInfo.cs b/src/MongoDB.Driver.GridFS/Properties/AssemblyInfo.cs
index d19d1222e2f..45a878a8830 100644
--- a/src/MongoDB.Driver.GridFS/Properties/AssemblyInfo.cs
+++ b/src/MongoDB.Driver.GridFS/Properties/AssemblyInfo.cs
@@ -25,4 +25,4 @@
 // Required for most of the reflection usage in Xamarin.iOS/Xamarin.Mac.
 [assembly: Preserve(AllMembers = true)]
 
-[assembly: InternalsVisibleTo("MongoDB.Driver.GridFS.Tests")]
+[assembly: InternalsVisibleTo("MongoDB.Driver.GridFS.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")]
diff --git a/src/MongoDB.Driver/Etherna.MongoDB.Driver.csproj b/src/MongoDB.Driver/Etherna.MongoDB.Driver.csproj
index a59f3a599ec..46766e57565 100644
--- a/src/MongoDB.Driver/Etherna.MongoDB.Driver.csproj
+++ b/src/MongoDB.Driver/Etherna.MongoDB.Driver.csproj
@@ -19,7 +19,7 @@
 
   <ItemGroup>
     <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.0" />
-    <PackageReference Include="MongoDB.Libmongocrypt" Version="1.10.0" />
+    <PackageReference Include="MongoDB.Libmongocrypt" Version="1.11.0" />
   </ItemGroup>
 
   <ItemGroup>
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Optimizers/AstSimplifier.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Optimizers/AstSimplifier.cs
index 3614c06f848..48fb600e90f 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Optimizers/AstSimplifier.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Ast/Optimizers/AstSimplifier.cs
@@ -16,7 +16,6 @@
 using Etherna.MongoDB.Bson;
 using Etherna.MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions;
 using Etherna.MongoDB.Driver.Linq.Linq3Implementation.Ast.Filters;
-using Etherna.MongoDB.Driver.Linq.Linq3Implementation.Ast.Stages;
 using Etherna.MongoDB.Driver.Linq.Linq3Implementation.Ast.Visitors;
 
 namespace Etherna.MongoDB.Driver.Linq.Linq3Implementation.Ast.Optimizers
@@ -37,6 +36,48 @@ public static TNode SimplifyAndConvert<TNode>(TNode node)
         }
         #endregion
 
+        public override AstNode VisitCondExpression(AstCondExpression node)
+        {
+            // { $cond : [{ $eq : [expr1, null] }, null, expr2] }
+            if (node.If is AstBinaryExpression binaryIfpression &&
+                binaryIfpression.Operator == AstBinaryOperator.Eq &&
+                binaryIfpression.Arg1 is AstExpression expr1 &&
+                binaryIfpression.Arg2 is AstConstantExpression constantComparandExpression &&
+                constantComparandExpression.Value == BsonNull.Value &&
+                node.Then is AstConstantExpression constantThenExpression &&
+                constantThenExpression.Value == BsonNull.Value &&
+                node.Else is AstExpression expr2)
+            {
+                // { $cond : [{ $eq : [expr, null] }, null, expr] } => expr
+                if (expr1 == expr2)
+                {
+                    return Visit(expr2);
+                }
+
+                // { $cond : [{ $eq : [expr, null] }, null, { $toT : expr }] } => { $toT : expr } for operators that map null to null
+                if (expr2 is AstUnaryExpression unaryElseExpression &&
+                    OperatorMapsNullToNull(unaryElseExpression.Operator) &&
+                    unaryElseExpression.Arg == expr1)
+                {
+                    return Visit(expr2);
+                }
+            }
+
+            return base.VisitCondExpression(node);
+
+            static bool OperatorMapsNullToNull(AstUnaryOperator @operator)
+            {
+                return @operator switch
+                {
+                    AstUnaryOperator.ToDecimal => true,
+                    AstUnaryOperator.ToDouble => true,
+                    AstUnaryOperator.ToInt => true,
+                    AstUnaryOperator.ToLong => true,
+                    _ => false
+                };
+            }
+        }
+
         public override AstNode VisitFieldOperationFilter(AstFieldOperationFilter node)
         {
             node = (AstFieldOperationFilter)base.VisitFieldOperationFilter(node);
@@ -281,6 +322,22 @@ bool TrySimplifyAsLet(AstGetFieldExpression node, out AstExpression simplified)
             }
         }
 
+        public override AstNode VisitLetExpression(AstLetExpression node)
+        {
+            node = (AstLetExpression)base.VisitLetExpression(node);
+
+            // { $let : { vars : { var : expr }, in : "$$var" } } => expr
+            if (node.Vars.Count == 1 &&
+                node.Vars[0].Var.Name is string varName &&
+                node.In is AstVarExpression varExpression &&
+                varExpression.Name == varName)
+            {
+                return node.Vars[0].Value;
+            }
+
+            return node;
+        }
+
         public override AstNode VisitMapExpression(AstMapExpression node)
         {
             // { $map : { input : <input>, as : "v", in : "$$v.x" } } => { $getField : { field : "x", input : <input> } }
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/SerializationHelper.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/SerializationHelper.cs
index a39ee290aec..dcc6a90a72a 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/SerializationHelper.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/SerializationHelper.cs
@@ -21,6 +21,7 @@
 using Etherna.MongoDB.Bson.Serialization.Options;
 using Etherna.MongoDB.Bson.Serialization.Serializers;
 using Etherna.MongoDB.Driver.Linq.Linq3Implementation.Serializers;
+using Etherna.MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators;
 
 namespace Etherna.MongoDB.Driver.Linq.Linq3Implementation.Misc
 {
@@ -35,6 +36,11 @@ public static void EnsureRepresentationIsArray(Expression expression, IBsonSeria
             }
         }
 
+        public static void EnsureRepresentationIsNumeric(Expression expression, AggregationExpression translation)
+        {
+            EnsureRepresentationIsNumeric(expression, translation.Serializer);
+        }
+
         public static void EnsureRepresentationIsNumeric(Expression expression, IBsonSerializer serializer)
         {
             var representation = GetRepresentation(serializer);
@@ -56,6 +62,11 @@ public static BsonType GetRepresentation(IBsonSerializer serializer)
                 return GetRepresentation(downcastingSerializer.DerivedSerializer);
             }
 
+            if (serializer is IEnumUnderlyingTypeSerializer enumUnderlyingTypeSerializer)
+            {
+                return GetRepresentation(enumUnderlyingTypeSerializer.EnumSerializer);
+            }
+
             if (serializer is IImpliedImplementationInterfaceSerializer impliedImplementationSerializer)
             {
                 return GetRepresentation(impliedImplementationSerializer.ImplementationSerializer);
@@ -82,6 +93,11 @@ public static BsonType GetRepresentation(IBsonSerializer serializer)
                 return keyValuePairSerializer.Representation;
             }
 
+            if (serializer is INullableSerializer nullableSerializer)
+            {
+                return GetRepresentation(nullableSerializer.ValueSerializer);
+            }
+
             // for backward compatibility assume that any remaining implementers of IBsonDocumentSerializer are represented as documents
             if (serializer is IBsonDocumentSerializer)
             {
@@ -97,6 +113,15 @@ public static BsonType GetRepresentation(IBsonSerializer serializer)
             return BsonType.Undefined;
         }
 
+        public static bool IsIntegerRepresentation(BsonType representation)
+        {
+            return representation switch
+            {
+                BsonType.Int32 or BsonType.Int64 => true,
+                _ => false
+            };
+        }
+
         public static bool IsNumericRepresentation(BsonType representation)
         {
             return representation switch
@@ -111,6 +136,29 @@ public static bool IsRepresentedAsDocument(IBsonSerializer serializer)
             return SerializationHelper.GetRepresentation(serializer) == BsonType.Document;
         }
 
+        public static bool IsRepresentedAsInteger(IBsonSerializer serializer)
+        {
+            var representation = GetRepresentation(serializer);
+            return IsIntegerRepresentation(representation);
+        }
+
+        public static bool IsRepresentedAsIntegerOrNullableInteger(AggregationExpression translation)
+        {
+            return IsRepresentedAsIntegerOrNullableInteger(translation.Serializer);
+        }
+
+        public static bool IsRepresentedAsIntegerOrNullableInteger(IBsonSerializer serializer)
+        {
+            if (serializer is INullableSerializer nullableSerializer)
+            {
+                return IsRepresentedAsInteger(nullableSerializer.ValueSerializer);
+            }
+            else
+            {
+                return IsRepresentedAsInteger(serializer);
+            }
+        }
+
         public static BsonValue SerializeValue(IBsonSerializer serializer, ConstantExpression constantExpression, Expression containingExpression)
         {
             var value = constantExpression.Value;
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/TypeExtensions.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/TypeExtensions.cs
index cad89047909..8ebe0777eca 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/TypeExtensions.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Misc/TypeExtensions.cs
@@ -22,6 +22,12 @@ namespace Etherna.MongoDB.Driver.Linq.Linq3Implementation.Misc
 {
     internal static class TypeExtensions
     {
+        private static readonly Type[] __dictionaryInterfaces =
+        {
+            typeof(IDictionary<,>),
+            typeof(IReadOnlyDictionary<,>)
+        };
+
         private static Type[] __tupleTypeDefinitions =
         {
             typeof(Tuple<>),
@@ -84,11 +90,11 @@ public static bool Implements(this Type type, Type @interface)
             return false;
         }
 
-        public static bool ImplementsIDictionary(this Type type, out Type keyType, out Type valueType)
+        public static bool ImplementsDictionaryInterface(this Type type, out Type keyType, out Type valueType)
         {
-            if (TryGetIDictionaryGenericInterface(type, out var idictionaryType))
+            if (TryGetGenericInterface(type, __dictionaryInterfaces, out var dictionaryInterface))
             {
-                var genericArguments = idictionaryType.GetGenericArguments();
+                var genericArguments = dictionaryInterface.GetGenericArguments();
                 keyType = genericArguments[0];
                 valueType = genericArguments[1];
                 return true;
@@ -255,28 +261,15 @@ public static bool IsValueTuple(this Type type)
                 type.IsConstructedGenericType &&
                 type.GetGenericTypeDefinition() is var typeDefinition &&
                 __valueTupleTypeDefinitions.Contains(typeDefinition);
-
         }
 
-        public static bool TryGetIDictionaryGenericInterface(this Type type, out Type idictionaryGenericInterface)
+        public static bool TryGetGenericInterface(this Type type, Type[] interfaceDefinitions, out Type genericInterface)
         {
-            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>))
-            {
-                idictionaryGenericInterface = type;
-                return true;
-            }
-
-            foreach (var interfaceType in type.GetInterfaces())
-            {
-                if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
-                {
-                    idictionaryGenericInterface = interfaceType;
-                    return true;
-                }
-            }
-
-            idictionaryGenericInterface = null;
-            return false;
+            genericInterface =
+                type.IsConstructedGenericType && interfaceDefinitions.Contains(type.GetGenericTypeDefinition()) ?
+                    type :
+                    type.GetInterfaces().FirstOrDefault(i => i.IsConstructedGenericType && interfaceDefinitions.Contains(i.GetGenericTypeDefinition()));
+            return genericInterface != null;
         }
 
         public static bool TryGetIEnumerableGenericInterface(this Type type, out Type ienumerableGenericInterface)
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/IDictionaryMethod.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/DictionaryMethod.cs
similarity index 89%
rename from src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/IDictionaryMethod.cs
rename to src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/DictionaryMethod.cs
index 61c5aa7a85b..e356b053677 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/IDictionaryMethod.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/DictionaryMethod.cs
@@ -18,7 +18,7 @@
 
 namespace Etherna.MongoDB.Driver.Linq.Linq3Implementation.Reflection
 {
-    internal static class IDictionaryMethod
+    internal static class DictionaryMethod
     {
         // public static methods
         public static bool IsGetItemWithStringMethod(MethodInfo method)
@@ -29,7 +29,7 @@ public static bool IsGetItemWithStringMethod(MethodInfo method)
                 method.GetParameters() is var parameters &&
                 parameters.Length == 1 &&
                 parameters[0].ParameterType == typeof(string) &&
-                method.DeclaringType.ImplementsIDictionary(out var keyType, out var valueType) &&
+                method.DeclaringType.ImplementsDictionaryInterface(out var keyType, out var valueType) &&
                 keyType == typeof(string) &&
                 method.ReturnType == valueType;
         }
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/BinaryExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/BinaryExpressionToAggregationExpressionTranslator.cs
index 2e91d702726..6e7aa113e62 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/BinaryExpressionToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/BinaryExpressionToAggregationExpressionTranslator.cs
@@ -15,7 +15,6 @@
 
 using System;
 using System.Linq.Expressions;
-using Etherna.MongoDB.Bson;
 using Etherna.MongoDB.Bson.Serialization;
 using Etherna.MongoDB.Bson.Serialization.Serializers;
 using Etherna.MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions;
@@ -82,6 +81,12 @@ public static AggregationExpression Translate(TranslationContext context, Binary
                 rightTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, rightExpression);
             }
 
+            if (IsArithmeticExpression(expression))
+            {
+                SerializationHelper.EnsureRepresentationIsNumeric(leftExpression, leftTranslation);
+                SerializationHelper.EnsureRepresentationIsNumeric(rightExpression, rightTranslation);
+            }
+
             var ast = expression.NodeType switch
             {
                 ExpressionType.Add => AstExpression.Add(leftTranslation.Ast, rightTranslation.Ast),
@@ -184,7 +189,7 @@ private static bool IsAddOrSubtractExpression(Expression expression)
 
         private static bool IsArithmeticExpression(BinaryExpression expression)
         {
-            return expression.Type.IsNumeric() && IsArithmeticOperator(expression.NodeType);
+            return expression.Type.IsNumericOrNullableNumeric() && IsArithmeticOperator(expression.NodeType);
         }
 
         private static bool IsArithmeticOperator(ExpressionType nodeType)
@@ -304,31 +309,29 @@ private static AggregationExpression TranslateEnumExpression(TranslationContext
                 leftTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, leftExpression);
                 rightTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, rightExpression);
 
+                AggregationExpression enumTranslation, operandTranslation;
                 if (IsEnumOrConvertEnumToUnderlyingType(leftExpression))
                 {
-                    serializer = leftTranslation.Serializer;
+                    enumTranslation = leftTranslation;
+                    operandTranslation = rightTranslation;
                 }
                 else
                 {
-                    serializer = rightTranslation.Serializer;
+                    enumTranslation = rightTranslation;
+                    operandTranslation = leftTranslation;
                 }
 
-                var representation = BsonType.Int32; // assume an integer representation unless we can determine otherwise
-                var valueSerializer = serializer;
-                if (valueSerializer is INullableSerializer nullableSerializer)
+                if (!SerializationHelper.IsRepresentedAsIntegerOrNullableInteger(enumTranslation))
                 {
-                    valueSerializer = nullableSerializer.ValueSerializer;
-                }
-                if (valueSerializer is IEnumUnderlyingTypeSerializer enumUnderlyingTypeSerializer &&
-                    enumUnderlyingTypeSerializer.EnumSerializer is IHasRepresentationSerializer withRepresentationSerializer)
-                {
-                    representation = withRepresentationSerializer.Representation;
+                    throw new ExpressionNotSupportedException(expression, because: "arithmetic on enums is only allowed when the enum is represented as an integer");
                 }
 
-                if (representation != BsonType.Int32 && representation != BsonType.Int64)
+                if (!SerializationHelper.IsRepresentedAsIntegerOrNullableInteger(operandTranslation))
                 {
-                    throw new ExpressionNotSupportedException(expression, because: "arithmetic on enums is only allowed when the enum is represented as an integer");
+                    throw new ExpressionNotSupportedException(expression, because: "the value being added to or subtracted from an enum must be represented as an integer");
                 }
+
+                serializer = enumTranslation.Serializer;
             }
             else
             {
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ConvertExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ConvertExpressionToAggregationExpressionTranslator.cs
index a3ba70d612a..7936e03587d 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ConvertExpressionToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/ConvertExpressionToAggregationExpressionTranslator.cs
@@ -30,95 +30,121 @@ public static AggregationExpression Translate(TranslationContext context, UnaryE
         {
             if (expression.NodeType == ExpressionType.Convert || expression.NodeType == ExpressionType.TypeAs)
             {
-                var expressionType = expression.Type;
-                if (expressionType == typeof(BsonValue))
+                var sourceExpression = expression.Operand;
+                var sourceType = sourceExpression.Type;
+                var targetType = expression.Type;
+
+                // handle double conversions like `(BsonValue)(object)x`
+                if (targetType == typeof(BsonValue) &&
+                    sourceExpression is UnaryExpression unarySourceExpression &&
+                    unarySourceExpression.NodeType == ExpressionType.Convert &&
+                    unarySourceExpression.Type == typeof(object))
                 {
-                    return TranslateConvertToBsonValue(context, expression, expression.Operand);
+                    sourceExpression = unarySourceExpression.Operand;
                 }
 
-                var operandExpression = expression.Operand;
-                var operandTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, operandExpression);
+                var sourceTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, sourceExpression);
+                return Translate(expression, sourceType, targetType, sourceTranslation);
+            }
 
-                if (expressionType == operandExpression.Type)
-                {
-                    return operandTranslation;
-                }
+            throw new ExpressionNotSupportedException(expression);
+        }
 
-                if (IsConvertEnumToUnderlyingType(expression))
-                {
-                    return TranslateConvertEnumToUnderlyingType(expression, operandTranslation);
-                }
+        private static AggregationExpression Translate(UnaryExpression expression, Type sourceType, Type targetType, AggregationExpression sourceTranslation)
+        {
+            if (targetType == sourceType)
+            {
+                return sourceTranslation;
+            }
 
-                if (IsConvertUnderlyingTypeToEnum(expression))
-                {
-                    return TranslateConvertUnderlyingTypeToEnum(expression, operandTranslation);
-                }
+            // from Nullable<T> must be handled before to Nullable<T>
+            if (IsConvertFromNullableType(sourceType))
+            {
+                return TranslateConvertFromNullableType(expression, sourceType, targetType, sourceTranslation);
+            }
 
-                if (IsConvertToBaseType(sourceType: operandExpression.Type, targetType: expressionType))
-                {
-                    return TranslateConvertToBaseType(expression, operandTranslation);
-                }
+            if (IsConvertToNullableType(targetType))
+            {
+                return TranslateConvertToNullableType(expression, sourceType, targetType, sourceTranslation);
+            }
 
-                if (IsConvertToDerivedType(sourceType: operandExpression.Type, targetType: expressionType))
-                {
-                    return TranslateConvertToDerivedType(expression, operandTranslation);
-                }
+            // from here on we know there are no longer any Nullable<T> types involved
 
-                if (expressionType.IsConstructedGenericType && expressionType.GetGenericTypeDefinition() == typeof(Nullable<>))
-                {
-                    var valueType = expressionType.GetGenericArguments()[0];
-                    if (operandExpression.Type == valueType)
-                    {
-                        // use the same AST but with a new nullable serializer
-                        var nullableSerializerType = typeof(NullableSerializer<>).MakeGenericType(valueType);
-                        var valueSerializerType = typeof(IBsonSerializer<>).MakeGenericType(valueType);
-                        var constructorInfo = nullableSerializerType.GetConstructor(new[] { valueSerializerType });
-                        var nullableSerializer = (IBsonSerializer)constructorInfo.Invoke(new[] { operandTranslation.Serializer });
-                        return new AggregationExpression(expression, operandTranslation.Ast, nullableSerializer);
-                    }
-                }
+            if (targetType == typeof(BsonValue))
+            {
+                return TranslateConvertToBsonValue(expression, sourceTranslation);
+            }
 
-                var ast = operandTranslation.Ast;
-                IBsonSerializer serializer;
-                if (expressionType.IsInterface)
-                {
-                    // when an expression is cast to an interface it's a no-op as far as we're concerned
-                    // and we can just use the serializer for the concrete type and members not defined in the interface will just be ignored
-                    serializer = operandTranslation.Serializer;
-                }
-                else
+            if (IsConvertEnumToUnderlyingType(sourceType, targetType))
+            {
+                return TranslateConvertEnumToUnderlyingType(expression, sourceType, targetType, sourceTranslation);
+            }
+
+            if (IsConvertUnderlyingTypeToEnum(sourceType, targetType))
+            {
+                return TranslateConvertUnderlyingTypeToEnum(expression, sourceType, targetType, sourceTranslation);
+            }
+
+            if (IsConvertEnumToEnum(sourceType, targetType))
+            {
+                return TranslateConvertEnumToEnum(expression, sourceType, targetType, sourceTranslation);
+            }
+
+            if (IsConvertToBaseType(sourceType, targetType))
+            {
+                return TranslateConvertToBaseType(expression, sourceType, targetType, sourceTranslation);
+            }
+
+            if (IsConvertToDerivedType(sourceType, targetType))
+            {
+                return TranslateConvertToDerivedType(expression, targetType, sourceTranslation);
+            }
+
+            var ast = sourceTranslation.Ast;
+            IBsonSerializer serializer;
+            if (targetType.IsInterface)
+            {
+                // when an expression is cast to an interface it's a no-op as far as we're concerned
+                // and we can just use the serializer for the concrete type and members not defined in the interface will just be ignored
+                serializer = sourceTranslation.Serializer;
+            }
+            else
+            {
+                AstExpression to;
+                switch (targetType.FullName)
                 {
-                    AstExpression to;
-                    switch (expressionType.FullName)
-                    {
-                        case "MongoDB.Bson.ObjectId": to = "objectId"; serializer = ObjectIdSerializer.Instance; break;
-                        case "System.Boolean": to = "bool"; serializer = BooleanSerializer.Instance; break;
-                        case "System.DateTime": to = "date"; serializer = DateTimeSerializer.Instance; break;
-                        case "System.Decimal": to = "decimal"; serializer = DecimalSerializer.Decimal128Instance; break; // not the default representation
-                        case "System.Double": to = "double"; serializer = DoubleSerializer.Instance; break;
-                        case "System.Int32": to = "int"; serializer = Int32Serializer.Instance; break;
-                        case "System.Int64": to = "long"; serializer = Int64Serializer.Instance; break;
-                        case "System.String": to = "string"; serializer = StringSerializer.Instance; break;
-                        default: throw new ExpressionNotSupportedException(expression, because: $"conversion to {expressionType} is not supported");
-                    }
-
-                    ast = AstExpression.Convert(ast, to);
+                    case "MongoDB.Bson.ObjectId": to = "objectId"; serializer = ObjectIdSerializer.Instance; break;
+                    case "System.Boolean": to = "bool"; serializer = BooleanSerializer.Instance; break;
+                    case "System.DateTime": to = "date"; serializer = DateTimeSerializer.Instance; break;
+                    case "System.Decimal": to = "decimal"; serializer = DecimalSerializer.Decimal128Instance; break; // not the default representation
+                    case "System.Double": to = "double"; serializer = DoubleSerializer.Instance; break;
+                    case "System.Int32": to = "int"; serializer = Int32Serializer.Instance; break;
+                    case "System.Int64": to = "long"; serializer = Int64Serializer.Instance; break;
+                    case "System.String": to = "string"; serializer = StringSerializer.Instance; break;
+                    default: throw new ExpressionNotSupportedException(expression, because: $"conversion to {targetType} is not supported");
                 }
 
-                return new AggregationExpression(expression, ast, serializer);
+                ast = AstExpression.Convert(ast, to);
             }
 
-            throw new ExpressionNotSupportedException(expression);
+            return new AggregationExpression(expression, ast, serializer);
         }
 
-        private static bool IsConvertEnumToUnderlyingType(UnaryExpression expression)
+        private static bool IsConvertEnumToEnum(Type sourceType, Type targetType)
         {
-            var sourceType = expression.Operand.Type;
-            var targetType = expression.Type;
+            return sourceType.IsEnum && targetType.IsEnum;
+        }
 
+        private static bool IsConvertEnumToUnderlyingType(Type sourceType, Type targetType)
+        {
             return
-                sourceType.IsEnumOrNullableEnum(out _, out var underlyingType) &&
-                targetType.IsSameAsOrNullableOf(underlyingType);
+                sourceType.IsEnum(out var underlyingType) &&
+                targetType == underlyingType;
+        }
+
+        private static bool IsConvertFromNullableType(Type sourceType)
+        {
+            return sourceType.IsNullable();
         }
 
         private static bool IsConvertToBaseType(Type sourceType, Type targetType)
@@ -131,88 +157,113 @@ private static bool IsConvertToDerivedType(Type sourceType, Type targetType)
             return targetType.IsSubclassOf(sourceType);
         }
 
-        private static bool IsConvertUnderlyingTypeToEnum(UnaryExpression expression)
+        private static bool IsConvertToNullableType(Type targetType)
         {
-            var sourceType = expression.Operand.Type;
-            var targetType = expression.Type;
+            return targetType.IsNullable();
+        }
 
+        private static bool IsConvertUnderlyingTypeToEnum(Type sourceType, Type targetType)
+        {
             return
-                targetType.IsEnumOrNullableEnum(out _, out var underlyingType) &&
-                sourceType.IsSameAsOrNullableOf(underlyingType);
+                targetType.IsEnum(out var underlyingType) &&
+                sourceType == underlyingType;
         }
 
-        private static AggregationExpression TranslateConvertToBaseType(UnaryExpression expression, AggregationExpression operandTranslation)
+        private static AggregationExpression TranslateConvertToBaseType(UnaryExpression expression, Type sourceType, Type targetType, AggregationExpression sourceTranslation)
         {
-            var baseType = expression.Type;
-            var derivedType = expression.Operand.Type;
-            var derivedTypeSerializer = operandTranslation.Serializer;
-            var downcastingSerializer = DowncastingSerializer.Create(baseType, derivedType, derivedTypeSerializer);
+            var derivedTypeSerializer = sourceTranslation.Serializer;
+            var downcastingSerializer = DowncastingSerializer.Create(targetType, sourceType, derivedTypeSerializer);
 
-            return new AggregationExpression(expression, operandTranslation.Ast, downcastingSerializer);
+            return new AggregationExpression(expression, sourceTranslation.Ast, downcastingSerializer);
         }
 
-        private static AggregationExpression TranslateConvertToDerivedType(UnaryExpression expression, AggregationExpression operandTranslation)
+        private static AggregationExpression TranslateConvertToDerivedType(UnaryExpression expression, Type targetType, AggregationExpression sourceTranslation)
         {
-            var serializer = BsonSerializer.LookupSerializer(expression.Type);
+            var serializer = BsonSerializer.LookupSerializer(targetType);
 
-            return new AggregationExpression(expression, operandTranslation.Ast, serializer);
+            return new AggregationExpression(expression, sourceTranslation.Ast, serializer);
         }
 
-        private static AggregationExpression TranslateConvertToBsonValue(TranslationContext context, UnaryExpression expression, Expression operand)
+        private static AggregationExpression TranslateConvertToBsonValue(UnaryExpression expression, AggregationExpression sourceTranslation)
         {
-            // handle double conversions like `(BsonValue)(object)x.Anything`
-            if (operand is UnaryExpression unaryExpression &&
-                unaryExpression.NodeType == ExpressionType.Convert &&
-                unaryExpression.Type == typeof(object))
-            {
-                operand = unaryExpression.Operand;
-            }
-
-            var operandTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, operand);
-
-            return new AggregationExpression(expression, operandTranslation.Ast, BsonValueSerializer.Instance);
+            return new AggregationExpression(expression, sourceTranslation.Ast, BsonValueSerializer.Instance);
         }
 
-        private static AggregationExpression TranslateConvertEnumToUnderlyingType(UnaryExpression expression, AggregationExpression operandTranslation)
+        private static AggregationExpression TranslateConvertEnumToEnum(UnaryExpression expression, Type sourceType, Type targetType, AggregationExpression sourceTranslation)
         {
-            var sourceType = expression.Operand.Type;
-            var targetType = expression.Type;
-
-            IBsonSerializer enumSerializer;
-            if (sourceType.IsNullable())
+            if (!sourceType.IsEnum)
             {
-                var nullableSerializer = (INullableSerializer)operandTranslation.Serializer;
-                enumSerializer = nullableSerializer.ValueSerializer;
+                throw new ExpressionNotSupportedException(expression, because: "source type is not an enum");
             }
-            else
+            if (!targetType.IsEnum)
             {
-                enumSerializer = operandTranslation.Serializer;
+                throw new ExpressionNotSupportedException(expression, because: "target type is not an enum");
             }
 
-            IBsonSerializer targetSerializer;
-            var enumUnderlyingTypeSerializer = EnumUnderlyingTypeSerializer.Create(enumSerializer);
-            if (targetType.IsNullable())
+            var sourceSerializer = sourceTranslation.Serializer;
+            if (sourceSerializer is IHasRepresentationSerializer sourceHasRepresentationSerializer &&
+                !SerializationHelper.IsNumericRepresentation(sourceHasRepresentationSerializer.Representation))
             {
-                targetSerializer = NullableSerializer.Create(enumUnderlyingTypeSerializer);
+                throw new ExpressionNotSupportedException(expression, because: "source enum is not represented as a number");
             }
-            else
+
+            var targetSerializer = EnumSerializer.Create(targetType);
+            return new AggregationExpression(expression, sourceTranslation.Ast, targetSerializer);
+        }
+
+        private static AggregationExpression TranslateConvertEnumToUnderlyingType(UnaryExpression expression, Type sourceType, Type targetType, AggregationExpression sourceTranslation)
+        {
+            var enumSerializer = sourceTranslation.Serializer;
+            var targetSerializer = EnumUnderlyingTypeSerializer.Create(enumSerializer);
+            return new AggregationExpression(expression, sourceTranslation.Ast, targetSerializer);
+        }
+
+        private static AggregationExpression TranslateConvertFromNullableType(UnaryExpression expression, Type sourceType, Type targetType, AggregationExpression sourceTranslation)
+        {
+            if (sourceType.IsNullable(out var sourceValueType))
             {
-                targetSerializer = enumUnderlyingTypeSerializer;
+                var (sourceVarBinding, sourceAst) = AstExpression.UseVarIfNotSimple("source", sourceTranslation.Ast);
+                var sourceNullableSerializer = (INullableSerializer)sourceTranslation.Serializer;
+                var sourceValueSerializer = sourceNullableSerializer.ValueSerializer;
+                var sourceValueAggregationExpression = new AggregationExpression(expression.Operand, sourceAst, sourceValueSerializer);
+                var convertTranslation = Translate(expression, sourceValueType, targetType, sourceValueAggregationExpression);
+
+                // note: we would have liked to throw a query execution error here if the value is null and the target type is not nullable but there is no way to do that in MQL
+                // so we just return null instead and the user must check for null themselves if they want to define what happens when the value is null
+                // but see SERVER-78092 and the proposed $error operator
+
+                var ast = AstExpression.Let(
+                    sourceVarBinding,
+                    AstExpression.Cond(AstExpression.Eq(sourceAst, BsonNull.Value), BsonNull.Value, convertTranslation.Ast));
+
+                return new AggregationExpression(expression, ast, convertTranslation.Serializer);
             }
 
-            return new AggregationExpression(expression, operandTranslation.Ast, targetSerializer);
+            throw new ExpressionNotSupportedException(expression, because: "sourceType is not nullable");
         }
 
-        private static AggregationExpression TranslateConvertUnderlyingTypeToEnum(UnaryExpression expression, AggregationExpression operandTranslation)
+        private static AggregationExpression TranslateConvertToNullableType(UnaryExpression expression, Type sourceType, Type targetType, AggregationExpression sourceTranslation)
         {
-            var targetType = expression.Type;
+            if (sourceType.IsNullable())
+            {
+                // ConvertFromNullableType should have been called first
+                throw new ExpressionNotSupportedException(expression, because: "sourceType is nullable");
+            }
 
-            var valueSerializer = operandTranslation.Serializer;
-            if (valueSerializer is INullableSerializer nullableSerializer)
+            if (targetType.IsNullable(out var targetValueType))
             {
-                valueSerializer = nullableSerializer.ValueSerializer;
+                var convertTranslation = Translate(expression, sourceType, targetValueType, sourceTranslation);
+                var nullableSerializer = NullableSerializer.Create(convertTranslation.Serializer);
+                return new AggregationExpression(expression, convertTranslation.Ast, nullableSerializer);
             }
 
+            throw new ExpressionNotSupportedException(expression, because: "targetType is not nullable");
+        }
+
+        private static AggregationExpression TranslateConvertUnderlyingTypeToEnum(UnaryExpression expression, Type sourceType, Type targetType, AggregationExpression sourceTranslation)
+        {
+            var valueSerializer = sourceTranslation.Serializer;
+
             IBsonSerializer targetSerializer;
             if (valueSerializer is IEnumUnderlyingTypeSerializer enumUnderlyingTypeSerializer)
             {
@@ -220,21 +271,10 @@ private static AggregationExpression TranslateConvertUnderlyingTypeToEnum(UnaryE
             }
             else
             {
-                var enumType = targetType;
-                if (targetType.IsNullable(out var wrappedType))
-                {
-                    enumType = wrappedType;
-                }
-
-                targetSerializer = EnumSerializer.Create(enumType);
-            }
-
-            if (targetType.IsNullableEnum())
-            {
-                targetSerializer = NullableSerializer.Create(targetSerializer);
+                targetSerializer = EnumSerializer.Create(targetType);
             }
 
-            return new AggregationExpression(expression, operandTranslation.Ast, targetSerializer);
+            return new AggregationExpression(expression, sourceTranslation.Ast, targetSerializer);
         }
     }
 }
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/AbsMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/AbsMethodToAggregationExpressionTranslator.cs
index f610b1847c7..a87b5db3091 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/AbsMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/AbsMethodToAggregationExpressionTranslator.cs
@@ -43,6 +43,7 @@ public static AggregationExpression Translate(TranslationContext context, Method
             {
                 var valueExpression = ConvertHelper.RemoveWideningConvert(arguments[0]);
                 var valueTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, valueExpression);
+                SerializationHelper.EnsureRepresentationIsNumeric(valueExpression, valueTranslation);
                 var ast = AstExpression.Abs(valueTranslation.Ast);
                 return new AggregationExpression(expression, ast, valueTranslation.Serializer);
             }
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CeilingMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CeilingMethodToAggregationExpressionTranslator.cs
index 59490e275b9..a690cbdebc2 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CeilingMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/CeilingMethodToAggregationExpressionTranslator.cs
@@ -32,6 +32,7 @@ public static AggregationExpression Translate(TranslationContext context, Method
             {
                 var argumentExpression = ConvertHelper.RemoveWideningConvert(arguments[0]);
                 var argumentTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, argumentExpression);
+                SerializationHelper.EnsureRepresentationIsNumeric(argumentExpression, argumentTranslation);
                 var ast = AstExpression.Ceil(argumentTranslation.Ast);
                 var serializer = BsonSerializer.LookupSerializer(expression.Type);
                 return new AggregationExpression(expression, ast, serializer);
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/DateTimeAddOrSubtractMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/DateTimeAddOrSubtractMethodToAggregationExpressionTranslator.cs
index db4b081ee2b..447fa1d4a8a 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/DateTimeAddOrSubtractMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/DateTimeAddOrSubtractMethodToAggregationExpressionTranslator.cs
@@ -144,12 +144,9 @@ public static AggregationExpression Translate(TranslationContext context, Method
                         {
                             throw new ExpressionNotSupportedException(valueExpression, expression);
                         }
-                        var representation = timeSpanSerializer.Representation;
+                        SerializationHelper.EnsureRepresentationIsNumeric(valueExpression, timeSpanSerializer);
+
                         var serializerUnits = timeSpanSerializer.Units;
-                        if (representation != BsonType.Int32 && representation != BsonType.Int64 && representation != BsonType.Double)
-                        {
-                            throw new ExpressionNotSupportedException(valueExpression, expression);
-                        }
                         (unit, amount) = serializerUnits switch
                         {
                             TimeSpanUnits.Ticks => ("millisecond", AstExpression.Divide(valueTranslation.Ast, (double)TimeSpan.TicksPerMillisecond)),
@@ -174,6 +171,8 @@ public static AggregationExpression Translate(TranslationContext context, Method
                 else
                 {
                     var valueTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, valueExpression);
+                    SerializationHelper.EnsureRepresentationIsNumeric(valueExpression, valueTranslation);
+
                     (unit, amount) = method.Name switch
                     {
                         "AddTicks" => ("millisecond", AstExpression.Divide(valueTranslation.Ast, (double)TimeSpan.TicksPerMillisecond)),
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ExpMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ExpMethodToAggregationExpressionTranslator.cs
index d8e3ade3472..410a64c4940 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ExpMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ExpMethodToAggregationExpressionTranslator.cs
@@ -32,6 +32,7 @@ public static AggregationExpression Translate(TranslationContext context, Method
             {
                 var argumentExpression = ConvertHelper.RemoveWideningConvert(arguments[0]);
                 var argumentTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, argumentExpression);
+                SerializationHelper.EnsureRepresentationIsNumeric(argumentExpression, argumentTranslation);
                 var ast = AstExpression.Exp(argumentTranslation.Ast);
                 return new AggregationExpression(expression, ast, new DoubleSerializer());
             }
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/FloorMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/FloorMethodToAggregationExpressionTranslator.cs
index 343a17480d9..26888e33705 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/FloorMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/FloorMethodToAggregationExpressionTranslator.cs
@@ -32,6 +32,7 @@ public static AggregationExpression Translate(TranslationContext context, Method
             {
                 var argumentExpression = ConvertHelper.RemoveWideningConvert(arguments[0]);
                 var argumentTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, argumentExpression);
+                SerializationHelper.EnsureRepresentationIsNumeric(argumentExpression, argumentTranslation);
                 var ast = AstExpression.Floor(argumentTranslation.Ast);
                 var serializer = BsonSerializer.LookupSerializer(expression.Type);
                 return new AggregationExpression(expression, ast, serializer);
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/GetItemMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/GetItemMethodToAggregationExpressionTranslator.cs
index e5b30b00f44..295363e9c1a 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/GetItemMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/GetItemMethodToAggregationExpressionTranslator.cs
@@ -55,7 +55,7 @@ public static AggregationExpression Translate(TranslationContext context, Expres
                 return TranslateIListGetItemWithInt(context, expression, sourceExpression, arguments[0]);
             }
 
-            if (IDictionaryMethod.IsGetItemWithStringMethod(method))
+            if (DictionaryMethod.IsGetItemWithStringMethod(method))
             {
                 return TranslateIDictionaryGetItemWithString(context, expression, sourceExpression, arguments[0]);
             }
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/IndexOfAnyMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/IndexOfAnyMethodToAggregationExpressionTranslator.cs
index 987c99a4fc0..d46743f0d16 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/IndexOfAnyMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/IndexOfAnyMethodToAggregationExpressionTranslator.cs
@@ -115,6 +115,7 @@ string TranslateAnyOf(ReadOnlyCollection<Expression> arguments)
 
                 var startIndexExpression = arguments[1];
                 var startIndexTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, startIndexExpression);
+                SerializationHelper.EnsureRepresentationIsNumeric(startIndexExpression, startIndexTranslation);
                 return AstExpression.UseVarIfNotSimple("startIndex", startIndexTranslation.Ast);
             }
 
@@ -127,6 +128,7 @@ string TranslateAnyOf(ReadOnlyCollection<Expression> arguments)
 
                 var countExpression = arguments[2];
                 var countTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, countExpression);
+                SerializationHelper.EnsureRepresentationIsNumeric(countExpression, countTranslation);
                 return AstExpression.UseVarIfNotSimple("count", countTranslation.Ast);
             }
 
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/IndexOfMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/IndexOfMethodToAggregationExpressionTranslator.cs
index 51de8f81303..c0b8c462fd8 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/IndexOfMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/IndexOfMethodToAggregationExpressionTranslator.cs
@@ -83,8 +83,18 @@ public static AggregationExpression Translate(TranslationContext context, Method
             {
                 var objectTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, objectExpression);
                 var valueTranslation = TranslateValue();
-                var startIndexTranslation = startIndexExpression == null ? null : ExpressionToAggregationExpressionTranslator.Translate(context, startIndexExpression);
-                var countTranslation = countExpression == null ? null : ExpressionToAggregationExpressionTranslator.Translate(context, countExpression);
+                AggregationExpression startIndexTranslation = null;
+                if (startIndexExpression != null)
+                {
+                    startIndexTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, startIndexExpression);
+                    SerializationHelper.EnsureRepresentationIsNumeric(startIndexExpression, startIndexTranslation);
+                }
+                AggregationExpression countTranslation = null;
+                if (countExpression != null)
+                {
+                    countTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, countExpression);
+                    SerializationHelper.EnsureRepresentationIsNumeric(countExpression, countTranslation);
+                }
                 var ordinal = GetOrdinalFromComparisonType();
 
                 var endAst = CreateEndAst(startIndexTranslation?.Ast, countTranslation?.Ast);
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/LogMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/LogMethodToAggregationExpressionTranslator.cs
index c60bc6a2fb5..a95685e064b 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/LogMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/LogMethodToAggregationExpressionTranslator.cs
@@ -32,6 +32,7 @@ public static AggregationExpression Translate(TranslationContext context, Method
             {
                 var argumentExpression = ConvertHelper.RemoveWideningConvert(arguments[0]);
                 var argumentTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, argumentExpression);
+                SerializationHelper.EnsureRepresentationIsNumeric(argumentExpression, argumentTranslation);
                 AstExpression ast;
                 if (method.Is(MathMethod.LogWithNewBase))
                 {
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/PowMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/PowMethodToAggregationExpressionTranslator.cs
index 79aae68c1c6..ca3d64f87b1 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/PowMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/PowMethodToAggregationExpressionTranslator.cs
@@ -32,8 +32,10 @@ public static AggregationExpression Translate(TranslationContext context, Method
             {
                 var xExpression = ConvertHelper.RemoveWideningConvert(arguments[0]);
                 var xTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, xExpression);
+                SerializationHelper.EnsureRepresentationIsNumeric(xExpression, xTranslation);
                 var yExpression = ConvertHelper.RemoveWideningConvert(arguments[1]);
                 var yTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, yExpression);
+                SerializationHelper.EnsureRepresentationIsNumeric(yExpression, yTranslation);
                 var ast = AstExpression.Pow(xTranslation.Ast, yTranslation.Ast);
                 return new AggregationExpression(expression, ast, new DoubleSerializer());
             }
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/RangeMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/RangeMethodToAggregationExpressionTranslator.cs
index 031a8641c1c..a1a1f004684 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/RangeMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/RangeMethodToAggregationExpressionTranslator.cs
@@ -34,10 +34,14 @@ public static AggregationExpression Translate(TranslationContext context, Method
             {
                 var startExpression = arguments[0];
                 var startTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, startExpression);
-                var (startVar, startAst) = AstExpression.UseVarIfNotSimple("start", startTranslation.Ast);
+                SerializationHelper.EnsureRepresentationIsNumeric(startExpression, startTranslation);
                 var countExpression = arguments[1];
                 var countTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, countExpression);
+                SerializationHelper.EnsureRepresentationIsNumeric(countExpression, countTranslation);
+
+                var (startVar, startAst) = AstExpression.UseVarIfNotSimple("start", startTranslation.Ast);
                 var (countVar, countAst) = AstExpression.UseVarIfNotSimple("count", countTranslation.Ast);
+
                 var ast = AstExpression.Let(
                     startVar,
                     countVar,
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/RoundMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/RoundMethodToAggregationExpressionTranslator.cs
index da58bdeb44d..34a98e72cdb 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/RoundMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/RoundMethodToAggregationExpressionTranslator.cs
@@ -46,12 +46,14 @@ public static AggregationExpression Translate(TranslationContext context, Method
             {
                 var argumentExpression = ConvertHelper.RemoveWideningConvert(arguments[0]);
                 var argumentTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, argumentExpression);
+                SerializationHelper.EnsureRepresentationIsNumeric(argumentExpression, argumentTranslation);
 
                 AstExpression ast;
                 if (method.IsOneOf(__roundWithPlaceMethods))
                 {
                     var placeExpression = arguments[1];
                     var placeTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, placeExpression);
+                    SerializationHelper.EnsureRepresentationIsNumeric(placeExpression, placeTranslation);
                     ast = AstExpression.Round(argumentTranslation.Ast, placeTranslation.Ast);
                 }
                 else
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/SqrtMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/SqrtMethodToAggregationExpressionTranslator.cs
index 327c2dde33e..4c3bf4fab20 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/SqrtMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/SqrtMethodToAggregationExpressionTranslator.cs
@@ -32,6 +32,7 @@ public static AggregationExpression Translate(TranslationContext context, Method
             {
                 var argumentExpression = ConvertHelper.RemoveWideningConvert(arguments[0]);
                 var argumentTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, argumentExpression);
+                SerializationHelper.EnsureRepresentationIsNumeric(argumentExpression, argumentTranslation);
                 var ast = AstExpression.Sqrt(argumentTranslation.Ast);
                 return new AggregationExpression(expression, ast, new DoubleSerializer());
             }
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/SubstringMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/SubstringMethodToAggregationExpressionTranslator.cs
index 2b1fc4f07bb..4790110f022 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/SubstringMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/SubstringMethodToAggregationExpressionTranslator.cs
@@ -53,6 +53,7 @@ private static AggregationExpression TranslateHelper(TranslationContext context,
         {
             var stringTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, stringExpression);
             var startIndexTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, startIndexExpression);
+            SerializationHelper.EnsureRepresentationIsNumeric(startIndexExpression, startIndexTranslation);
 
             AstExpression ast;
             if (lengthExpression == null)
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/TruncateMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/TruncateMethodToAggregationExpressionTranslator.cs
index 39932cb5a6f..7246b81b6a5 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/TruncateMethodToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/TruncateMethodToAggregationExpressionTranslator.cs
@@ -73,6 +73,7 @@ public static AggregationExpression Translate(TranslationContext context, Method
             {
                 var argumentExpression = ConvertHelper.RemoveWideningConvert(arguments[0]);
                 var argumentTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, argumentExpression);
+                SerializationHelper.EnsureRepresentationIsNumeric(argumentExpression, argumentTranslation);
                 var ast = AstExpression.Trunc(argumentTranslation.Ast);
                 return new AggregationExpression(expression, ast, argumentTranslation.Serializer);
             }
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NegateExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NegateExpressionToAggregationExpressionTranslator.cs
index 08757429de3..057b8afa1b3 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NegateExpressionToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NegateExpressionToAggregationExpressionTranslator.cs
@@ -26,7 +26,7 @@ public static AggregationExpression Translate(TranslationContext context, UnaryE
             if (expression.NodeType == ExpressionType.Negate)
             {
                 var operandTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, expression.Operand);
-                SerializationHelper.EnsureRepresentationIsNumeric(expression, operandTranslation.Serializer);
+                SerializationHelper.EnsureRepresentationIsNumeric(expression, operandTranslation);
 
                 var ast = AstExpression.Subtract(0, operandTranslation.Ast);
                 return new AggregationExpression(expression, ast, operandTranslation.Serializer);
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewArrayInitExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewArrayInitExpressionToAggregationExpressionTranslator.cs
index c0f337f35f1..e682522de22 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewArrayInitExpressionToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewArrayInitExpressionToAggregationExpressionTranslator.cs
@@ -13,8 +13,11 @@
 * limitations under the License.
 */
 
+using System;
 using System.Collections.Generic;
 using System.Linq.Expressions;
+using Etherna.MongoDB.Bson.Serialization;
+using Etherna.MongoDB.Bson.Serialization.Serializers;
 using Etherna.MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions;
 
 namespace Etherna.MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators
@@ -24,14 +27,29 @@ internal static class NewArrayInitExpressionToAggregationExpressionTranslator
         public static AggregationExpression Translate(TranslationContext context, NewArrayExpression expression)
         {
             var items = new List<AstExpression>();
+            IBsonSerializer itemSerializer = null;
             foreach (var itemExpression in expression.Expressions)
             {
                 var itemTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, itemExpression);
                 items.Add(itemTranslation.Ast);
+                itemSerializer ??= itemTranslation.Serializer;
+
+                // make sure all items are serialized using the same serializer
+                if (!itemTranslation.Serializer.Equals(itemSerializer))
+                {
+                    throw new ExpressionNotSupportedException(expression, because: "all items in the array must be serialized using the same serializer");
+                }
             }
+
             var ast = AstExpression.ComputedArray(items);
-            var serializer = context.KnownSerializersRegistry.GetSerializer(expression);
-            return new AggregationExpression(expression, ast, serializer);
+
+            var arrayType = expression.Type;
+            var itemType = arrayType.GetElementType();
+            itemSerializer ??= BsonSerializer.LookupSerializer(itemType); // if the array is empty itemSerializer will be null
+            var arraySerializerType = typeof(ArraySerializer<>).MakeGenericType(itemType);
+            var arraySerializer = (IBsonSerializer)Activator.CreateInstance(arraySerializerType, itemSerializer);
+
+            return new AggregationExpression(expression, ast, arraySerializer);
         }
     }
 }
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/GetItemMethodToFilterFieldTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/GetItemMethodToFilterFieldTranslator.cs
index 1223f0fed9b..40f96373bf5 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/GetItemMethodToFilterFieldTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToFilterTranslators/ToFilterFieldTranslators/GetItemMethodToFilterFieldTranslator.cs
@@ -53,9 +53,9 @@ public static AstFilterField Translate(TranslationContext context, Expression ex
                 return TranslateIListGetItemWithInt(context, expression, fieldExpression, arguments[0]);
             }
 
-            if (IDictionaryMethod.IsGetItemWithStringMethod(method))
+            if (DictionaryMethod.IsGetItemWithStringMethod(method))
             {
-                return TranslateIDictionaryGetItemWithString(context, expression, fieldExpression, arguments[0]);
+                return TranslateDictionaryGetItemWithString(context, expression, fieldExpression, arguments[0]);
             }
 
             throw new ExpressionNotSupportedException(expression);
@@ -80,7 +80,7 @@ private static AstFilterField TranslateIListGetItemWithInt(TranslationContext co
             return ArrayIndexExpressionToFilterFieldTranslator.Translate(context, expression, fieldExpression, indexExpression);
         }
 
-        private static AstFilterField TranslateIDictionaryGetItemWithString(TranslationContext context, Expression expression, Expression fieldExpression, Expression keyExpression)
+        private static AstFilterField TranslateDictionaryGetItemWithString(TranslationContext context, Expression expression, Expression fieldExpression, Expression keyExpression)
         {
             var field = ExpressionToFilterFieldTranslator.Translate(context, fieldExpression);
             var key = keyExpression.GetConstantValue<string>(containingExpression: expression);
diff --git a/src/MongoDB.Driver/ProjectionDefinition.cs b/src/MongoDB.Driver/ProjectionDefinition.cs
index ad357dd79db..ab9d1007828 100644
--- a/src/MongoDB.Driver/ProjectionDefinition.cs
+++ b/src/MongoDB.Driver/ProjectionDefinition.cs
@@ -306,6 +306,21 @@ public Expression<Func<TSource, TProjection>> Expression
 
         /// <inheritdoc />
         public override RenderedProjectionDefinition<TProjection> Render(IBsonSerializer<TSource> sourceSerializer, IBsonSerializerRegistry serializerRegistry, LinqProvider linqProvider)
+        {
+            if (linqProvider == LinqProvider.V2)
+            {
+                // this is slightly wrong because we're not actually rendering for a Find
+                // but this is required to avoid a regression with LINQ2
+                return RenderForFind(sourceSerializer, serializerRegistry, linqProvider);
+            }
+            else
+            {
+                return linqProvider.GetAdapter().TranslateExpressionToProjection(_expression, sourceSerializer, serializerRegistry, translationOptions: null);
+            }
+        }
+
+        /// <inheritdoc />
+        internal override RenderedProjectionDefinition<TProjection> RenderForFind(IBsonSerializer<TSource> sourceSerializer, IBsonSerializerRegistry serializerRegistry, LinqProvider linqProvider)
         {
             return linqProvider.GetAdapter().TranslateExpressionToFindProjection(_expression, sourceSerializer, serializerRegistry);
         }
diff --git a/src/MongoDB.Driver/ProjectionDefinitionBuilder.cs b/src/MongoDB.Driver/ProjectionDefinitionBuilder.cs
index 265282a5296..198b655323e 100644
--- a/src/MongoDB.Driver/ProjectionDefinitionBuilder.cs
+++ b/src/MongoDB.Driver/ProjectionDefinitionBuilder.cs
@@ -544,7 +544,9 @@ public ProjectionDefinition<TSource> Exclude(Expression<Func<TSource, object>> f
         /// </returns>
         public ProjectionDefinition<TSource, TProjection> Expression<TProjection>(Expression<Func<TSource, TProjection>> expression)
         {
-            return new ExpressionProjectionDefinition<TSource, TProjection>(expression, null);
+            // TODO: replace FindExpressionProjectionDefinition with ExpressionProjectionDefinition when LINQ2 is removed
+            // in the meantime we have to keep using FindExpressionProjectionDefinition here for compatibility with LINQ2
+            return new FindExpressionProjectionDefinition<TSource, TProjection>(expression);
         }
 
         /// <summary>
diff --git a/src/MongoDB.Driver/Properties/AssemblyInfo.cs b/src/MongoDB.Driver/Properties/AssemblyInfo.cs
index 14ec55e555a..c4ac8277c9f 100644
--- a/src/MongoDB.Driver/Properties/AssemblyInfo.cs
+++ b/src/MongoDB.Driver/Properties/AssemblyInfo.cs
@@ -25,11 +25,12 @@
 // Required for most of the reflection usage in Xamarin.iOS/Xamarin.Mac.
 [assembly: Preserve(AllMembers = true)]
 
-[assembly: InternalsVisibleTo("MongoDB.Driver.Legacy")]
-[assembly: InternalsVisibleTo("MongoDB.Driver.Legacy.TestHelpers")]
-[assembly: InternalsVisibleTo("MongoDB.Driver.Legacy.Tests")]
-[assembly: InternalsVisibleTo("MongoDB.Driver.Tests")]
-[assembly: InternalsVisibleTo("MongoDB.Driver.TestHelpers")]
-[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
-[assembly: InternalsVisibleTo("MongoDB.Driver.Benchmarks")]
+[assembly: InternalsVisibleTo("MongoDB.Driver.Legacy, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")]
+[assembly: InternalsVisibleTo("MongoDB.Driver.Legacy.TestHelpers, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")]
+[assembly: InternalsVisibleTo("MongoDB.Driver.Legacy.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")]
+[assembly: InternalsVisibleTo("MongoDB.Driver.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")]
+[assembly: InternalsVisibleTo("MongoDB.Driver.TestHelpers, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")]
+[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
+[assembly: InternalsVisibleTo("MongoDB.Driver.Benchmarks, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")]
+[assembly: InternalsVisibleTo("MongoDB.Analyzer.MQLGenerator, PublicKey=002400000480000094000000060200000024000052534131000400000100010035287f0d3883c0a075c88e0cda3ce93b621003ecbd5e920d4a8c7238564f4d2f4f68116aca28c9b21341dc3a877679c14556192b2b2f5fe2c11d624e0894d308ff7b94bf6fd72aef1b41017ffe2572e99019d1c61963e68cd0ed67734a42cb333b808e3867cbe631937214e32e409fb1fa62fdb69d494c2530e64a40e417d6ee")]
 
diff --git a/src/MongoDB.Driver/Support/ReflectionExtensions.cs b/src/MongoDB.Driver/Support/ReflectionExtensions.cs
index b3c6ad6d09c..aba0c9068b7 100644
--- a/src/MongoDB.Driver/Support/ReflectionExtensions.cs
+++ b/src/MongoDB.Driver/Support/ReflectionExtensions.cs
@@ -72,6 +72,21 @@ public static bool IsNumeric(this Type type)
                 type == typeof(Decimal128);
         }
 
+        public static bool IsNumericOrNullableNumeric(this Type type)
+        {
+            if (type.IsConstructedGenericType &&
+                type.GetGenericTypeDefinition() is var genericTypeDefinition &&
+                genericTypeDefinition == typeof(Nullable<>))
+            {
+                var valueType = type.GetGenericArguments()[0];
+                return IsNumeric(valueType);
+            }
+            else
+            {
+                return IsNumeric(type);
+            }
+        }
+
         public static bool IsConvertibleToEnum(this Type type)
         {
             return