diff --git a/src/Vogen/GenerateCastingOperators.cs b/src/Vogen/GenerateCastingOperators.cs
index 63013b04ef..3bd42647d1 100644
--- a/src/Vogen/GenerateCastingOperators.cs
+++ b/src/Vogen/GenerateCastingOperators.cs
@@ -41,12 +41,25 @@ public static string GenerateImplementations(VoWorkItem item, TypeDeclarationSyn
 
         if (item.Config.FromPrimitiveCasting == CastOperator.Implicit)
         {
-            sb.AppendLine(
-                $$"""
-                          public static implicit operator {{className}}({{itemUnderlyingType}} value) {
-                            return new {{className}}(value);
-                  }
-                  """);
+            if (item.NormalizeInputMethod is not null)
+            {
+                sb.AppendLine(
+                    $$"""
+                              public static implicit operator {{className}}({{itemUnderlyingType}} value) {
+                                return new {{className}}({{className}}.NormalizeInput(value));
+                      }
+                      """);
+                
+            }
+            else
+            {
+                sb.AppendLine(
+                    $$"""
+                              public static implicit operator {{className}}({{itemUnderlyingType}} value) {
+                                return new {{className}}(value);
+                      }
+                      """);
+            }
         }
 
         if (sb.Length == 0)
diff --git a/tests/ConsumerTests/BugFix624.cs b/tests/ConsumerTests/BugFix624.cs
new file mode 100644
index 0000000000..3458d75c64
--- /dev/null
+++ b/tests/ConsumerTests/BugFix624.cs
@@ -0,0 +1,36 @@
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Text.Json.Serialization.Metadata;
+using SystemTextJsonSerializer = System.Text.Json.JsonSerializer;
+
+namespace ConsumerTests.BugFixTests.BugFix639;
+
+[ValueObject<string>(fromPrimitiveCasting: CastOperator.Implicit)]
+public partial class C_With
+{
+    private static string NormalizeInput(string input) => input.ToUpper();
+}
+
+[ValueObject<string>(fromPrimitiveCasting: CastOperator.Implicit)]
+public partial class C_Without;
+
+/// <summary>
+/// Fixes bug https://github.com/SteveDunn/Vogen/issues/639 where any
+/// `NormalizeInput` method was not called when implicitly converting a primitive to a value object
+/// </summary>
+public class Tests
+{
+    [Fact]
+    public void Should_call_if_present()
+    {
+        C_With vo = "abc";
+        vo.Value.Should().Be("ABC");
+    }
+
+    [Fact]
+    public void Should_not_call_if_not_present()
+    {
+        C_Without vo = "abc";
+        vo.Value.Should().Be("abc");
+    }
+}
diff --git a/tests/ConsumerTests/Casting/ForClasses.cs b/tests/ConsumerTests/Casting/ForClasses.cs
index edf0632f48..7893e17216 100644
--- a/tests/ConsumerTests/Casting/ForClasses.cs
+++ b/tests/ConsumerTests/Casting/ForClasses.cs
@@ -46,4 +46,20 @@ public void Implicit_both_ways()
         Class_implicit_both_ways vo2 = prim;
         vo2.Should().Be(vo);
     }
+
+    [Fact]
+    public void Implicit_both_ways_with_normalization()
+    {
+        using var _ = new AssertionScope();
+        
+        var vo = Class_implicit_both_ways_with_normalization.From("abc");
+
+        string prim = vo;
+
+        prim.Should().Be(vo.Value);
+        
+        Class_implicit_both_ways_with_normalization vo2 = prim;
+        vo2.Should().Be(vo);
+        vo2.Value.Should().Be("ABC");
+    }
 }
diff --git a/tests/ConsumerTests/Casting/ForStructs.cs b/tests/ConsumerTests/Casting/ForStructs.cs
index 9e505fce8a..d358482404 100644
--- a/tests/ConsumerTests/Casting/ForStructs.cs
+++ b/tests/ConsumerTests/Casting/ForStructs.cs
@@ -46,4 +46,21 @@ public void Implicit_both_ways()
         Struct_implicit_both_ways vo2 = prim;
         vo2.Should().Be(vo);
     }
+    
+    [Fact]
+    public void Implicit_both_ways_with_normalization()
+    {
+        using var _ = new AssertionScope();
+        
+        var vo = Struct_implicit_both_ways_with_normalization.From("abc");
+
+        string prim = vo;
+
+        prim.Should().Be(vo.Value);
+        
+        Struct_implicit_both_ways_with_normalization vo2 = prim;
+        vo2.Should().Be(vo);
+        vo2.Value.Should().Be("ABC");
+    }
+    
 }
diff --git a/tests/ConsumerTests/Casting/Types.cs b/tests/ConsumerTests/Casting/Types.cs
index 566700d95b..e4875a347e 100644
--- a/tests/ConsumerTests/Casting/Types.cs
+++ b/tests/ConsumerTests/Casting/Types.cs
@@ -15,6 +15,12 @@ public partial class Class_implicit_both_ways
 {
 }
 
+[ValueObject(typeof(string), toPrimitiveCasting: CastOperator.Implicit, fromPrimitiveCasting: CastOperator.Implicit)]
+public partial class Class_implicit_both_ways_with_normalization
+{
+    private static string NormalizeInput(string input) => input.ToUpper();
+}
+
 [ValueObject<string>(toPrimitiveCasting: CastOperator.None, fromPrimitiveCasting: CastOperator.None)]
 public partial class Class_default_generic
 {
@@ -35,6 +41,12 @@ public partial class Struct_implicit_both_ways
 {
 }
 
+[ValueObject(typeof(string), toPrimitiveCasting: CastOperator.Implicit, fromPrimitiveCasting: CastOperator.Implicit)]
+public partial class Struct_implicit_both_ways_with_normalization
+{
+    private static string NormalizeInput(string input) => input.ToUpper();
+}
+
 [ValueObject<string>(toPrimitiveCasting: CastOperator.None, fromPrimitiveCasting: CastOperator.None)]
 public partial class Struct_default_generic
 {