diff --git a/src/Generator/AST/Utils.cs b/src/Generator/AST/Utils.cs
index 986b5585..47836867 100644
--- a/src/Generator/AST/Utils.cs
+++ b/src/Generator/AST/Utils.cs
@@ -36,9 +36,6 @@ namespace CppSharp.AST
             if (method.IsDestructor)
                 return true;
 
-            if (method.OperatorKind == CXXOperatorKind.Equal)
-                return true;
-
             if (method.Access == AccessSpecifier.Private && !method.IsOverride && !method.IsExplicitlyGenerated)
                 return true;
 
diff --git a/src/Generator/Generators/CSharp/CSharpSources.cs b/src/Generator/Generators/CSharp/CSharpSources.cs
index 8cedbf44..e0764de8 100644
--- a/src/Generator/Generators/CSharp/CSharpSources.cs
+++ b/src/Generator/Generators/CSharp/CSharpSources.cs
@@ -1009,8 +1009,34 @@ internal static bool {Helpers.TryGetNativeToManagedMappingIdentifier}(IntPtr nat
 
         private void GenerateFieldSetter(Field field, Class @class, QualifiedType fieldType)
         {
+            if (field.Type.IsClass() && !field.Type.IsPointer())
+            {
+                if (field.Type.TryGetClass(out Class fieldClass))
+                {
+                    var caop = fieldClass.Methods.FirstOrDefault(m => m.OperatorKind == CXXOperatorKind.Equal);
+                    if (caop != null)
+                    {
+                        var fieldName = ((Class)field.Namespace).Layout.Fields.First(
+                            f => f.FieldPtr == field.OriginalPtr).Name;
+                        WriteLine($"var dest = new __IntPtr(&((__Internal*)__Instance)->{fieldName});");
+                        WriteLine($"var src = value.{Helpers.InstanceIdentifier};");
+
+                        var typeName = TypePrinter.PrintNative(fieldClass);
+                        if (IsInternalClassNested(fieldClass))
+                            typeName.RemoveNamespace();
+
+                        WriteLine($"{fieldClass}.__Internal.OperatorEqual(dest, src);");
+                        //UnindentAndWriteCloseBrace();
+
+                        return;
+                    }
+                }
+            }
+
+
             string returnVar;
             Type type = field.Type.Desugar();
+
             var arrayType = type as ArrayType;
             if (arrayType != null && @class.IsValueType)
             {
@@ -1481,6 +1507,11 @@ internal static bool {Helpers.TryGetNativeToManagedMappingIdentifier}(IntPtr nat
                     continue;
                 }
 
+                // We only use the copy assignment operator internally,
+                // so do not generate a public method wrapper for it
+                if (method.OperatorKind == CXXOperatorKind.Equal)
+                    continue;
+
                 GenerateMethod(method, @class);
             }
 
diff --git a/src/Generator/Passes/ValidateOperatorsPass.cs b/src/Generator/Passes/ValidateOperatorsPass.cs
index b1f86db1..bf1dbd92 100644
--- a/src/Generator/Passes/ValidateOperatorsPass.cs
+++ b/src/Generator/Passes/ValidateOperatorsPass.cs
@@ -55,6 +55,9 @@ namespace CppSharp.Passes
                 // The conversion operators can be overloaded
                 case CXXOperatorKind.Conversion:
                 case CXXOperatorKind.ExplicitConversion:
+
+                // Copy assignment operator is used internally
+                case CXXOperatorKind.Equal:
                     return true;
 
                 // The comparison operators can be overloaded if their return type is bool
@@ -127,7 +130,6 @@ namespace CppSharp.Passes
                 case CXXOperatorKind.PipePipe:
 
                 // These operators cannot be overloaded.
-                case CXXOperatorKind.Equal:
                 case CXXOperatorKind.Comma:
                 case CXXOperatorKind.ArrowStar:
                 case CXXOperatorKind.Arrow: