diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs
index 1adfc8c01..4b10a089d 100644
--- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs
+++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs
@@ -43,7 +43,7 @@ public class OpenApiSchema : IOpenApiAnnotatable, IOpenApiExtensible, IOpenApiRe
         /// 
         /// $vocabulary- used in meta-schemas to identify the vocabularies available for use in schemas described by that meta-schema.
         /// 
-        public virtual string Vocabulary { get; set; }
+        public virtual IDictionary Vocabulary { get; set; }
 
         /// 
         /// $dynamicRef - an applicator that allows for deferring the full resolution until runtime, at which point it is resolved each time it is encountered while evaluating an instance
@@ -55,16 +55,6 @@ public class OpenApiSchema : IOpenApiAnnotatable, IOpenApiExtensible, IOpenApiRe
         /// 
         public virtual string DynamicAnchor { get; set; }
 
-        /// 
-        /// $recursiveAnchor - used to construct recursive schemas i.e one that has a reference to its own root, identified by the empty fragment URI reference ("#")
-        /// 
-        public virtual string RecursiveAnchor { get; set; }
-
-        /// 
-        /// $recursiveRef - used to construct recursive schemas i.e one that has a reference to its own root, identified by the empty fragment URI reference ("#")
-        /// 
-        public virtual string RecursiveRef { get; set; }
-
         /// 
         /// $defs - reserves a location for schema authors to inline re-usable JSON Schemas into a more general schema. 
         /// The keyword does not directly affect the validation result
@@ -358,11 +348,9 @@ public OpenApiSchema(OpenApiSchema schema)
             Id = schema?.Id ?? Id;
             Schema = schema?.Schema ?? Schema;
             Comment = schema?.Comment ?? Comment;
-            Vocabulary = schema?.Vocabulary ?? Vocabulary;
+            Vocabulary = schema?.Vocabulary != null ? new Dictionary(schema.Vocabulary) : null;
             DynamicAnchor = schema?.DynamicAnchor ?? DynamicAnchor;
             DynamicRef = schema?.DynamicRef ?? DynamicRef;
-            RecursiveAnchor = schema?.RecursiveAnchor ?? RecursiveAnchor;
-            RecursiveRef = schema?.RecursiveRef ?? RecursiveRef;
             Definitions = schema?.Definitions != null ? new Dictionary(schema.Definitions) : null;
             UnevaluatedProperties = schema?.UnevaluatedProperties ?? UnevaluatedProperties;
             V31ExclusiveMaximum = schema?.V31ExclusiveMaximum ?? V31ExclusiveMaximum;
@@ -490,22 +478,22 @@ public void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
             SerializeTypeProperty(Type, writer, version);
 
             // allOf
-            writer.WriteOptionalCollection(OpenApiConstants.AllOf, AllOf, (w, s) => s.SerializeAsV3(w));
+            writer.WriteOptionalCollection(OpenApiConstants.AllOf, AllOf, callback);
 
             // anyOf
-            writer.WriteOptionalCollection(OpenApiConstants.AnyOf, AnyOf, (w, s) => s.SerializeAsV3(w));
+            writer.WriteOptionalCollection(OpenApiConstants.AnyOf, AnyOf, callback);
 
             // oneOf
-            writer.WriteOptionalCollection(OpenApiConstants.OneOf, OneOf, (w, s) => s.SerializeAsV3(w));
+            writer.WriteOptionalCollection(OpenApiConstants.OneOf, OneOf, callback);
 
             // not
-            writer.WriteOptionalObject(OpenApiConstants.Not, Not, (w, s) => s.SerializeAsV3(w));
+            writer.WriteOptionalObject(OpenApiConstants.Not, Not, callback);
 
             // items
-            writer.WriteOptionalObject(OpenApiConstants.Items, Items, (w, s) => s.SerializeAsV3(w));
+            writer.WriteOptionalObject(OpenApiConstants.Items, Items, callback);
 
             // properties
-            writer.WriteOptionalMap(OpenApiConstants.Properties, Properties, (w, s) => s.SerializeAsV3(w));
+            writer.WriteOptionalMap(OpenApiConstants.Properties, Properties, callback);
 
             // additionalProperties
             if (AdditionalPropertiesAllowed)
@@ -513,7 +501,7 @@ public void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
                 writer.WriteOptionalObject(
                     OpenApiConstants.AdditionalProperties,
                     AdditionalProperties,
-                    (w, s) => s.SerializeAsV3(w));
+                    callback);
             }
             else
             {
@@ -536,7 +524,7 @@ public void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
             }
 
             // discriminator
-            writer.WriteOptionalObject(OpenApiConstants.Discriminator, Discriminator, (w, s) => s.SerializeAsV3(w));
+            writer.WriteOptionalObject(OpenApiConstants.Discriminator, Discriminator, callback);
 
             // readOnly
             writer.WriteProperty(OpenApiConstants.ReadOnly, ReadOnly, false);
@@ -548,7 +536,7 @@ public void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
             writer.WriteOptionalObject(OpenApiConstants.Xml, Xml, (w, s) => s.SerializeAsV2(w));
 
             // externalDocs
-            writer.WriteOptionalObject(OpenApiConstants.ExternalDocs, ExternalDocs, (w, s) => s.SerializeAsV3(w));
+            writer.WriteOptionalObject(OpenApiConstants.ExternalDocs, ExternalDocs, callback);
 
             // example
             writer.WriteOptionalObject(OpenApiConstants.Example, Example, (w, e) => w.WriteAny(e));
@@ -557,7 +545,7 @@ public void SerializeInternal(IOpenApiWriter writer, OpenApiSpecVersion version,
             writer.WriteProperty(OpenApiConstants.Deprecated, Deprecated, false);
 
             // extensions
-            writer.WriteExtensions(Extensions, OpenApiSpecVersion.OpenApi3_0);
+            writer.WriteExtensions(Extensions, version);
 
             writer.WriteEndObject();
         }
@@ -574,12 +562,10 @@ internal void WriteV31Properties(IOpenApiWriter writer)
             writer.WriteProperty(OpenApiConstants.Id, Id);
             writer.WriteProperty(OpenApiConstants.DollarSchema, Schema);
             writer.WriteProperty(OpenApiConstants.Comment, Comment);
-            writer.WriteProperty(OpenApiConstants.Vocabulary, Vocabulary);
-            writer.WriteOptionalMap(OpenApiConstants.Defs, Definitions, (w, s) => s.SerializeAsV3(w));
+            writer.WriteOptionalMap(OpenApiConstants.Vocabulary, Vocabulary, (w, s) => w.WriteValue(s));
+            writer.WriteOptionalMap(OpenApiConstants.Defs, Definitions, (w, s) => s.SerializeAsV31(w));
             writer.WriteProperty(OpenApiConstants.DynamicRef, DynamicRef);
             writer.WriteProperty(OpenApiConstants.DynamicAnchor, DynamicAnchor);
-            writer.WriteProperty(OpenApiConstants.RecursiveAnchor, RecursiveAnchor);
-            writer.WriteProperty(OpenApiConstants.RecursiveRef, RecursiveRef);
             writer.WriteProperty(OpenApiConstants.V31ExclusiveMaximum, V31ExclusiveMaximum);
             writer.WriteProperty(OpenApiConstants.V31ExclusiveMinimum, V31ExclusiveMinimum);            
             writer.WriteProperty(OpenApiConstants.UnevaluatedProperties, UnevaluatedProperties, false);
diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs
index 535a6a522..759959344 100644
--- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs
+++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs
@@ -74,16 +74,12 @@ internal OpenApiSchemaReference(OpenApiSchema target, string referenceId)
         /// 
         public override string Comment { get => Target.Comment; set => Target.Comment = value; }
         /// 
-        public override string Vocabulary { get => Target.Vocabulary; set => Target.Vocabulary = value; }
+        public override IDictionary Vocabulary { get => Target.Vocabulary; set => Target.Vocabulary = value; }
         /// 
         public override string DynamicRef { get => Target.DynamicRef; set => Target.DynamicRef = value; }
         /// 
         public override string DynamicAnchor { get => Target.DynamicAnchor; set => Target.DynamicAnchor = value; }
         /// 
-        public override string RecursiveAnchor { get => Target.RecursiveAnchor; set => Target.RecursiveAnchor = value; }
-        /// 
-        public override string RecursiveRef { get => Target.RecursiveRef; set => Target.RecursiveRef = value; }
-        /// 
         public override IDictionary Definitions { get => Target.Definitions; set => Target.Definitions = value; }
         /// 
         public override decimal? V31ExclusiveMaximum { get => Target.V31ExclusiveMaximum; set => Target.V31ExclusiveMaximum = value; }
diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs
index 7757c710f..05ce240c9 100644
--- a/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs
+++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiSchemaDeserializer.cs
@@ -32,7 +32,7 @@ internal static partial class OpenApiV31Deserializer
             },
             {
                 "$vocabulary",
-                (o, n, _) => o.Vocabulary = n.GetScalarValue()
+                (o, n, _) => o.Vocabulary = n.CreateSimpleMap(LoadBool)
             },
             {
                 "$dynamicRef",
@@ -42,14 +42,6 @@ internal static partial class OpenApiV31Deserializer
                 "$dynamicAnchor",
                 (o, n, _) => o.DynamicAnchor = n.GetScalarValue()
             },
-            {
-                "$recursiveAnchor",
-                (o, n, _) => o.RecursiveAnchor = n.GetScalarValue()
-            },
-            {
-                "$recursiveRef",
-                (o, n, _) => o.RecursiveRef = n.GetScalarValue()
-            },
             {
                 "$defs",
                 (o, n, t) => o.Definitions = n.CreateMap(LoadSchema, t)
diff --git a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs
index d6c9d0fcf..a037dc3c1 100644
--- a/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs
+++ b/src/Microsoft.OpenApi/Reader/V31/OpenApiV31Deserializer.cs
@@ -145,6 +145,11 @@ private static string LoadString(ParseNode node)
             return node.GetScalarValue();
         }
 
+        private static bool LoadBool(ParseNode node)
+        {
+            return bool.Parse(node.GetScalarValue());
+        }
+
         private static (string, string) GetReferenceIdAndExternalResource(string pointer)
         {
             /* Check whether the reference pointer is a URL
diff --git a/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs b/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs
index f6102f316..a1a74e815 100644
--- a/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs
+++ b/src/Microsoft.OpenApi/Writers/OpenApiWriterExtensions.cs
@@ -272,6 +272,25 @@ public static void WriteOptionalMap(
             }
         }
 
+        /// 
+        /// Write the optional Open API element map (string to string mapping).
+        /// 
+        /// The Open API writer.
+        /// The property name.
+        /// The map values.
+        /// The map element writer action.
+        public static void WriteOptionalMap(
+            this IOpenApiWriter writer,
+            string name,
+            IDictionary elements,
+            Action action)
+        {
+            if (elements != null && elements.Any())
+            {
+                writer.WriteMapInternal(name, elements, action);
+            }
+        }
+
         /// 
         /// Write the optional Open API element map.
         /// 
diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs
index cacb1ed86..6df59331e 100644
--- a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs
+++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/OpenApiSchemaTests.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
 // Licensed under the MIT license. 
 
 using System.Collections.Generic;
@@ -404,5 +404,51 @@ public void LoadSchemaWithNullableExtensionAsV31Works(string filePath)
             // Assert
             schema.Type.Should().BeEquivalentTo(new string[] { "string", "null" });
         }
+
+        [Fact]
+        public void SerializeSchemaWithJsonSchemaKeywordsWorks()
+        {
+            // Arrange
+            var expected = @"$id: https://example.com/schemas/person.schema.yaml
+$schema: https://json-schema.org/draft/2020-12/schema
+$comment: A schema defining a person object with optional references to dynamic components.
+$vocabulary:
+  https://json-schema.org/draft/2020-12/vocab/core: true
+  https://json-schema.org/draft/2020-12/vocab/applicator: true
+  https://json-schema.org/draft/2020-12/vocab/validation: true
+  https://json-schema.org/draft/2020-12/vocab/meta-data: false
+  https://json-schema.org/draft/2020-12/vocab/format-annotation: false
+$dynamicAnchor: addressDef
+title: Person
+required:
+  - name
+type: object
+properties:
+  name:
+    $comment: The person's full name
+    type: string
+  age:
+    $comment: Age must be a non-negative integer
+    minimum: 0
+    type: integer
+  address:
+    $comment: Reference to an address definition which can change dynamically
+    $dynamicRef: '#addressDef'
+description: Schema for a person object
+";
+            var path = Path.Combine(SampleFolderPath, "schemaWithJsonSchemaKeywords.yaml");
+
+            // Act
+            var schema = OpenApiModelFactory.Load(path, OpenApiSpecVersion.OpenApi3_1, out _);
+
+            // serialization
+            var writer = new StringWriter();
+            schema.SerializeAsV31(new OpenApiYamlWriter(writer));
+            var schemaString = writer.ToString();
+
+            // Assert
+            schema.Vocabulary.Keys.Count.Should().Be(5);
+            schemaString.MakeLineBreaksEnvironmentNeutral().Should().Be(expected.MakeLineBreaksEnvironmentNeutral());
+        }
     }
 }
diff --git a/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiSchema/schemaWithJsonSchemaKeywords.yaml b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiSchema/schemaWithJsonSchemaKeywords.yaml
new file mode 100644
index 000000000..3d88cffcd
--- /dev/null
+++ b/test/Microsoft.OpenApi.Readers.Tests/V31Tests/Samples/OpenApiSchema/schemaWithJsonSchemaKeywords.yaml
@@ -0,0 +1,41 @@
+$schema: "https://json-schema.org/draft/2020-12/schema"
+$id: "https://example.com/schemas/person.schema.yaml"
+$comment: "A schema defining a person object with optional references to dynamic components."
+$vocabulary:
+  "https://json-schema.org/draft/2020-12/vocab/core": true
+  "https://json-schema.org/draft/2020-12/vocab/applicator": true
+  "https://json-schema.org/draft/2020-12/vocab/validation": true
+  "https://json-schema.org/draft/2020-12/vocab/meta-data": false
+  "https://json-schema.org/draft/2020-12/vocab/format-annotation": false
+
+title: "Person"
+description: "Schema for a person object"
+type: "object"
+
+properties:
+  name:
+    type: "string"
+    $comment: "The person's full name"
+  age:
+    type: "integer"
+    minimum: 0
+    $comment: "Age must be a non-negative integer"
+  address:
+    $dynamicRef: "#addressDef"
+    $comment: "Reference to an address definition which can change dynamically"
+  
+required:
+  - name
+
+$dynamicAnchor: "addressDef"
+definitions:
+  address:
+    $dynamicAnchor: "addressDef"
+    type: "object"
+    properties:
+      street:
+        type: "string"
+      city:
+        type: "string"
+      postalCode:
+        type: "string"
diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
index 3a7fdbd57..dabe527c7 100644
--- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
+++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt
@@ -901,8 +901,6 @@ namespace Microsoft.OpenApi.Models
         public virtual System.Collections.Generic.IDictionary PatternProperties { get; set; }
         public virtual System.Collections.Generic.IDictionary Properties { get; set; }
         public virtual bool ReadOnly { get; set; }
-        public virtual string RecursiveAnchor { get; set; }
-        public virtual string RecursiveRef { get; set; }
         public virtual Microsoft.OpenApi.Models.OpenApiReference Reference { get; set; }
         public virtual System.Collections.Generic.ISet Required { get; set; }
         public virtual string Schema { get; set; }
@@ -914,7 +912,7 @@ namespace Microsoft.OpenApi.Models
         public virtual bool UnresolvedReference { get; set; }
         public virtual decimal? V31ExclusiveMaximum { get; set; }
         public virtual decimal? V31ExclusiveMinimum { get; set; }
-        public virtual string Vocabulary { get; set; }
+        public virtual System.Collections.Generic.IDictionary Vocabulary { get; set; }
         public virtual bool WriteOnly { get; set; }
         public virtual Microsoft.OpenApi.Models.OpenApiXml Xml { get; set; }
         public virtual void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }
@@ -1243,8 +1241,6 @@ namespace Microsoft.OpenApi.Models.References
         public override System.Collections.Generic.IDictionary PatternProperties { get; set; }
         public override System.Collections.Generic.IDictionary Properties { get; set; }
         public override bool ReadOnly { get; set; }
-        public override string RecursiveAnchor { get; set; }
-        public override string RecursiveRef { get; set; }
         public override System.Collections.Generic.ISet Required { get; set; }
         public override string Schema { get; set; }
         public override string Title { get; set; }
@@ -1254,7 +1250,7 @@ namespace Microsoft.OpenApi.Models.References
         public override bool? UniqueItems { get; set; }
         public override decimal? V31ExclusiveMaximum { get; set; }
         public override decimal? V31ExclusiveMinimum { get; set; }
-        public override string Vocabulary { get; set; }
+        public override System.Collections.Generic.IDictionary Vocabulary { get; set; }
         public override bool WriteOnly { get; set; }
         public override Microsoft.OpenApi.Models.OpenApiXml Xml { get; set; }
         public override void SerializeAsV2(Microsoft.OpenApi.Writers.IOpenApiWriter writer) { }
@@ -1849,6 +1845,7 @@ namespace Microsoft.OpenApi.Writers
     {
         public static void WriteOptionalCollection(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IEnumerable elements, System.Action action) { }
         public static void WriteOptionalCollection(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IEnumerable elements, System.Action action) { }
+        public static void WriteOptionalMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action) { }
         public static void WriteOptionalMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action) { }
         public static void WriteOptionalMap(this Microsoft.OpenApi.Writers.IOpenApiWriter writer, string name, System.Collections.Generic.IDictionary elements, System.Action action)
             where T : Microsoft.OpenApi.Interfaces.IOpenApiElement { }