diff --git a/configuration/encryption-and-signing-credentials.md b/configuration/encryption-and-signing-credentials.md
index ac5b6ca..a6ce932 100644
--- a/configuration/encryption-and-signing-credentials.md
+++ b/configuration/encryption-and-signing-credentials.md
@@ -6,6 +6,7 @@ To protect the tokens it issues, OpenIddict uses 2 types of credentials:
 
 > [!NOTE]
 > Tokens generated using the opt-in ASP.NET Core Data Protection integration rely on their own key ring, distinct from the credentials discussed in this documentation.
+>
 > For more information about Data Protection, visit [ASP.NET Core Data Protection](https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/introduction).
 
 ## Registering credentials in the authorization server options
@@ -35,6 +36,7 @@ services.AddOpenIddict()
 > [!NOTE]
 > `options.AddEphemeralEncryptionKey()` generates an asymmetric RSA key which is not directly used as-is to encrypt the tokens but is used to encrypt an
 > intermediate *per-token* symmetric key with which the token content is first encrypted using [AES](https://datatracker.ietf.org/doc/html/rfc7518#section-5.2.6).
+>
 > For more information about this mechanism, read [Key Encryption with RSAES OAEP](https://datatracker.ietf.org/doc/html/rfc7518#section-4.3).
 
 ### Registering a development certificate
@@ -110,7 +112,7 @@ var data = certificate.Export(X509ContentType.Pfx, string.Empty);
 The best place to store your certificates will depend on your host:
   - For IIS applications, storing the certificates in the machine store is the recommended option.
   - On Azure, certificates can be uploaded and exposed to Azure App Services applications using the special `WEBSITE_LOAD_CERTIFICATES` flag.
-For more information, visit https://docs.microsoft.com/en-us/azure/app-service/configure-ssl-certificate-in-code
+For more information, visit [Use a TLS/SSL certificate in your code in Azure App Service](https://docs.microsoft.com/en-us/azure/app-service/configure-ssl-certificate-in-code).
 
 ## Importing credentials in the API/resource validation options
 
diff --git a/configuration/index.md b/configuration/index.md
index ea08c32..60d5dd5 100644
--- a/configuration/index.md
+++ b/configuration/index.md
@@ -1,3 +1,3 @@
-# Configuration and settings
+# Configuration
 
 OpenIddict 3.0 comes with sensible defaults, but depending on the scenarios, the default settings can be amended to change how OpenIddict reacts to requests.
\ No newline at end of file
diff --git a/configuration/toc.yml b/configuration/toc.yml
index 0e2f771..99e1b95 100644
--- a/configuration/toc.yml
+++ b/configuration/toc.yml
@@ -13,9 +13,6 @@
 - name: Encryption and signing credentials
   href: encryption-and-signing-credentials.md
 
-- name: MongoDB integration
-  href: mongodb-integration.md
-
 - name: Proof Key for Code Exchange
   href: proof-key-for-code-exchange.md
 
diff --git a/guide/choosing-the-right-flow.md b/guides/choosing-the-right-flow.md
similarity index 100%
rename from guide/choosing-the-right-flow.md
rename to guides/choosing-the-right-flow.md
diff --git a/guide/choosing-the-right-flow/authorization-code-flow.png b/guides/choosing-the-right-flow/authorization-code-flow.png
similarity index 100%
rename from guide/choosing-the-right-flow/authorization-code-flow.png
rename to guides/choosing-the-right-flow/authorization-code-flow.png
diff --git a/guide/choosing-the-right-flow/client-credentials-flow.png b/guides/choosing-the-right-flow/client-credentials-flow.png
similarity index 100%
rename from guide/choosing-the-right-flow/client-credentials-flow.png
rename to guides/choosing-the-right-flow/client-credentials-flow.png
diff --git a/guide/choosing-the-right-flow/consent-form.png b/guides/choosing-the-right-flow/consent-form.png
similarity index 100%
rename from guide/choosing-the-right-flow/consent-form.png
rename to guides/choosing-the-right-flow/consent-form.png
diff --git a/guide/choosing-the-right-flow/implicit-flow.png b/guides/choosing-the-right-flow/implicit-flow.png
similarity index 100%
rename from guide/choosing-the-right-flow/implicit-flow.png
rename to guides/choosing-the-right-flow/implicit-flow.png
diff --git a/guide/choosing-the-right-flow/resource-owner-password-flow.png b/guides/choosing-the-right-flow/resource-owner-password-flow.png
similarity index 100%
rename from guide/choosing-the-right-flow/resource-owner-password-flow.png
rename to guides/choosing-the-right-flow/resource-owner-password-flow.png
diff --git a/guide/getting-started.md b/guides/getting-started.md
similarity index 85%
rename from guide/getting-started.md
rename to guides/getting-started.md
index ae226ef..2519ab2 100644
--- a/guide/getting-started.md
+++ b/guides/getting-started.md
@@ -26,12 +26,11 @@ If you don't want to start from one of the recommended samples, you'll need to:
 
         services.AddDbContext<ApplicationDbContext>(options =>
         {
-            // Configure the context to use Microsoft SQL Server.
+            // Configure Entity Framework Core to use Microsoft SQL Server.
             options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
 
             // Register the entity sets needed by OpenIddict.
-            // Note: use the generic overload if you need
-            // to replace the default OpenIddict entities.
+            // Note: use the generic overload if you need to replace the default OpenIddict entities.
             options.UseOpenIddict();
         });
 
@@ -105,38 +104,18 @@ If you don't want to start from one of the recommended samples, you'll need to:
     ```csharp
     services.AddDbContext<ApplicationDbContext>(options =>
     {
-        // Configure the context to use Microsoft SQL Server.
+        // Configure Entity Framework Core to use Microsoft SQL Server.
         options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
 
         // Register the entity sets needed by OpenIddict.
-        // Note: use the generic overload if you need
-        // to replace the default OpenIddict entities.
+        // Note: use the generic overload if you need to replace the default OpenIddict entities.
         options.UseOpenIddict();
     });
     ```
 
-    > [!WARNING]
-    > If you change the default entity primary key (e.g. to `int` or `Guid` instead of `string`), make sure you use the `options.ReplaceDefaultEntities<TKey>()`
-    > core extension accepting a `TKey` generic argument and use the generic `options.UseOpenIddict<TKey>()` overload to configure EF Core to use the specified type:
-    >
-    >    ```csharp
-    >    services.AddOpenIddict()
-    >        .AddCore(options =>
-    >        {
-    >            // Configure OpenIddict to use the default entities with a custom key type.
-    >            options.UseEntityFrameworkCore()
-    >                   .UseDbContext<ApplicationDbContext>()
-    >                   .ReplaceDefaultEntities<Guid>();
-    >        });
-    >
-    >    services.AddDbContext<ApplicationDbContext>(options =>
-    >    {
-    >        // Configure the context to use Microsoft SQL Server.
-    >        options.UseSqlServer(configuration["Data:DefaultConnection:ConnectionString"]);
-    >
-    >        options.UseOpenIddict<Guid>();
-    >    });
-    >```
+    > [!NOTE]
+    > By default, the OpenIddict Entity Framework Core integration uses `string` as the default type for primary keys.
+    > To use a different type, read [Entity Framework Core integration : Use a custom primary key type](~/integrations/entity-framework-core.md#use-a-custom-primary-key-type).
 
   - **Create your own authorization controller:**
     Implementing a custom authorization controller is required to allow OpenIddict to create tokens based on the identities and claims you provide.
diff --git a/guide/index.md b/guides/index.md
similarity index 100%
rename from guide/index.md
rename to guides/index.md
diff --git a/guide/migration/20-to-30.md b/guides/migration/20-to-30.md
similarity index 100%
rename from guide/migration/20-to-30.md
rename to guides/migration/20-to-30.md
diff --git a/guide/toc.yml b/guides/toc.yml
similarity index 100%
rename from guide/toc.yml
rename to guides/toc.yml
diff --git a/index.md b/index.md
index a98add5..bb300b0 100644
--- a/index.md
+++ b/index.md
@@ -14,7 +14,7 @@ OpenIddict natively supports **[Entity Framework Core](https://www.nuget.org/pac
     <div class="col-md-4">
         <div class="panel panel-default" style="min-height: 120px;">
             <div class="panel-body">
-                <p><strong><a href="guide/index.md">Introduction</a></strong></p>
+                <p><strong><a href="guides/index.md">Introduction</a></strong></p>
                 <p>Read an introduction on OpenIddict and the reason it was created.</p>
             </div>
         </div>
@@ -22,7 +22,7 @@ OpenIddict natively supports **[Entity Framework Core](https://www.nuget.org/pac
     <div class="col-md-4">
         <div class="panel panel-default" style="min-height: 120px;">
             <div class="panel-body">
-                <p><strong><a href="guide/getting-started.md">Getting started</a></strong></p>
+                <p><strong><a href="guides/getting-started.md">Getting started</a></strong></p>
                 <p>Get started quickly by working through this step-by-step guide.</p>
             </div>
         </div>
diff --git a/integrations/entity-framework-core.md b/integrations/entity-framework-core.md
new file mode 100644
index 0000000..daefcf1
--- /dev/null
+++ b/integrations/entity-framework-core.md
@@ -0,0 +1,135 @@
+# Entity Framework Core integration
+
+## Basic configuration
+
+To configure OpenIddict to use Entity Framework Core as the database for applications, authorizations, scopes and tokens, you'll need to:
+  - **Reference the `OpenIddict.EntityFrameworkCore` package**:
+
+    ```xml
+    <PackageReference Include="OpenIddict.EntityFrameworkCore" Version="3.1.1" />
+    ```
+
+  - **Create a database context deriving from `DbContext` (or `IdentityDbContext` when using ASP.NET Core Identity)**:
+
+    ```csharp
+    public class ApplicationDbContext : DbContext
+    {
+        public ApplicationDbContext(DbContextOptions options)
+            : base(options)
+        {
+        }
+    }
+    ```
+
+  - **Configure OpenIddict to use the Entity Framework Core stores**:
+
+    ```csharp
+    services.AddOpenIddict()
+        .AddCore(options =>
+        {
+            options.UseEntityFrameworkCore()
+                   .UseDbContext<ApplicationDbContext>();
+        });
+    ```
+
+  - **Configure Entity Framework Core to register the OpenIddict entities in the model**:
+
+    ```csharp
+    services.AddDbContext<ApplicationDbContext>(options =>
+    {
+        // Configure the Entity Framework Core to use Microsoft SQL Server.
+        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
+
+        // Register the entity sets needed by OpenIddict.
+        options.UseOpenIddict();
+    });
+    ```
+
+  - **Use migrations or recreate the database to add the OpenIddict entities**.
+For more information, read [Migrations Overview](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/).
+
+## Advanced configuration
+
+### Use a custom primary key type
+
+By default, the Entity Framework Core integration uses `string` primary keys, which matches the default key type used by ASP.NET Core Identity.
+
+To use a different key type (e.g `int`, `long` or `Guid`):
+  - **Call the generic `ReplaceDefaultEntities<TKey>()` method to force OpenIddict to use the default entities with the specified key type**:
+
+    ```csharp
+    services.AddOpenIddict()
+        .AddCore(options =>
+        {
+            // Configure OpenIddict to use the default entities with a custom key type.
+            options.UseEntityFrameworkCore()
+                   .UseDbContext<ApplicationDbContext>()
+                   .ReplaceDefaultEntities<Guid>();
+        });
+    ```
+
+  - **Configure Entity Framework Core to include the default entities with the chosen key type in the model**:
+
+    ```csharp
+    services.AddDbContext<ApplicationDbContext>(options =>
+    {
+        // Configure Entity Framework Core to use Microsoft SQL Server.
+        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
+
+        // Register the entity sets needed by OpenIddict but use a custom key type.
+        options.UseOpenIddict<Guid>();
+    });
+    ```
+
+### Use custom entities
+
+For applications that require storing additional data alongside the properties used by OpenIddict, custom entities can be used. For that, you need to:
+  - **Create custom entities**:
+
+    ```csharp
+    public class CustomApplication : OpenIddictEntityFrameworkCoreApplication<long, CustomAuthorization, CustomToken>
+    {
+        public string CustomProperty { get; set; }
+    }
+
+    public class CustomAuthorization : OpenIddictEntityFrameworkCoreAuthorization<long, CustomApplication, CustomToken>
+    {
+        public string CustomProperty { get; set; }
+    }
+
+    public class CustomScope : OpenIddictEntityFrameworkCoreScope<long>
+    {
+        public string CustomProperty { get; set; }
+    }
+
+    public class CustomToken : OpenIddictEntityFrameworkCoreToken<long, CustomApplication, CustomAuthorization>
+    {
+        public string CustomProperty { get; set; }
+    }
+    ```
+
+  - **Call the generic `ReplaceDefaultEntities<TApplication, TAuthorization, TScope, TToken, TKey>()` method to force OpenIddict to use the custom entities**:
+
+    ```csharp
+    services.AddOpenIddict()
+        .AddCore(options =>
+        {
+            // Configure OpenIddict to use the custom entities.
+            options.UseEntityFrameworkCore()
+                   .UseDbContext<ApplicationDbContext>()
+                   .ReplaceDefaultEntities<CustomApplication, CustomAuthorization, CustomScope, CustomToken, long>();
+        });
+    ```
+
+  - **Configure Entity Framework Core to include the custom entities in the model**:
+
+    ```csharp
+    services.AddDbContext<ApplicationDbContext>(options =>
+    {
+        // Configure Entity Framework Core to use Microsoft SQL Server.
+        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
+
+        // Register the entity sets needed by OpenIddict but use the specified entities instead of the default ones.
+        options.UseOpenIddict<CustomApplication, CustomAuthorization, CustomScope, CustomToken, long>();
+    });
+    ```
\ No newline at end of file
diff --git a/integrations/index.md b/integrations/index.md
new file mode 100644
index 0000000..0889e47
--- /dev/null
+++ b/integrations/index.md
@@ -0,0 +1,6 @@
+# Integrations
+
+OpenIddict offers native integrations with popular Object–relational Mapping tools and Database Clients like Entity Framework 6 and Entity Framework Core or MongoDB.
+
+Documentation for integrations maintained by the OpenIddict community can be found in their respective repositories:
+- **[P41.OpenIddict.CouchDB](https://github.com/panoukos41/couchdb-openiddict)** by [Panos Athanasiou](https://github.com/panoukos41): CouchDB stores for OpenIddict.
\ No newline at end of file
diff --git a/configuration/mongodb-integration.md b/integrations/mongodb.md
similarity index 72%
rename from configuration/mongodb-integration.md
rename to integrations/mongodb.md
index 13f8f6f..0e35325 100644
--- a/configuration/mongodb-integration.md
+++ b/integrations/mongodb.md
@@ -1,12 +1,16 @@
 # MongoDB integration
 
+## Basic configuration
+
 To configure OpenIddict to use MongoDB as the database for applications, authorizations, scopes and tokens, you'll need to:
   - **Reference the `OpenIddict.MongoDb` package**:
+
     ```xml
     <PackageReference Include="OpenIddict.MongoDb" Version="3.1.1" />
     ```
 
   - **Configure OpenIddict to use the MongoDB stores**:
+
     ```csharp
     services.AddOpenIddict()
         .AddCore(options =>
@@ -34,6 +38,7 @@ To configure OpenIddict to use MongoDB as the database for applications, authori
 
   - **Create indexes to improve performance** (recommended): for that, you can use the following script to
 initialize the database and create the indexes used by the OpenIddict entities:
+
     ```csharp
     using System.Threading;
     using Microsoft.Extensions.DependencyInjection;
@@ -113,8 +118,7 @@ initialize the database and create the indexes used by the OpenIddict entities:
             {
                 // Note: partial filter expressions are not supported on Azure Cosmos DB.
                 // As a workaround, the expression and the unique constraint can be removed.
-                PartialFilterExpression =
-                    Builders<OpenIddictMongoDbToken>.Filter.Exists(token => token.ReferenceId),
+                PartialFilterExpression = Builders<OpenIddictMongoDbToken>.Filter.Exists(token => token.ReferenceId),
                 Unique = true
             }),
 
@@ -129,4 +133,64 @@ initialize the database and create the indexes used by the OpenIddict entities:
                 Background = true
             })
     });
-    ```
\ No newline at end of file
+    ```
+
+## Advanced configuration
+
+### Use custom entities
+
+For applications that require storing additional data alongside the properties used by OpenIddict, custom entities can be used. For that, you need to:
+  - **Create custom entities**:
+
+    ```csharp
+    public class CustomApplication : OpenIddictMongoDbApplication
+    {
+        public string CustomProperty { get; set; }
+    }
+
+    public class CustomAuthorization : OpenIddictMongoDbAuthorization
+    {
+        public string CustomProperty { get; set; }
+    }
+
+    public class CustomScope : OpenIddictMongoDbScope
+    {
+        public string CustomProperty { get; set; }
+    }
+
+    public class CustomToken : OpenIddictMongoDbToken
+    {
+        public string CustomProperty { get; set; }
+    }
+    ```
+
+  - **Configure MongoDb to use the custom entities**:
+
+    ```csharp
+    services.AddOpenIddict()
+        .AddCore(options =>
+        {
+            options.UseMongoDb()
+                   .ReplaceDefaultApplicationEntity<CustomApplication>()
+                   .ReplaceDefaultAuthorizationEntity<CustomAuthorization>()
+                   .ReplaceDefaultScopeEntity<CustomScope>()
+                   .ReplaceDefaultTokenEntity<CustomToken>();
+        });
+    ```
+
+### Use custom collection names
+
+By default, OpenIddict uses the `openiddict.[entity name]s` pattern to determine the default collection names.
+Applications that require using different collection names can use the `Set*CollectionName()` helpers:
+
+```csharp
+services.AddOpenIddict()
+    .AddCore(options =>
+    {
+        options.UseMongoDb()
+               .SetApplicationsCollectionName("custom-applications-collection")
+               .SetAuthorizationsCollectionName("custom-authorizations-collection")
+               .SetScopesCollectionName("custom-scopes-collection")
+               .SetTokensCollectionName("custom-tokens-collection");
+    });
+```
\ No newline at end of file
diff --git a/integrations/toc.yml b/integrations/toc.yml
new file mode 100644
index 0000000..f3a4a32
--- /dev/null
+++ b/integrations/toc.yml
@@ -0,0 +1,8 @@
+- name: Introduction
+  href: index.md
+
+- name: Entity Framework Core
+  href: entity-framework-core.md
+
+- name: MongoDB
+  href: mongodb.md
\ No newline at end of file
diff --git a/toc.yml b/toc.yml
index 05bfae8..0478206 100644
--- a/toc.yml
+++ b/toc.yml
@@ -1,11 +1,14 @@
 - name: User guides
-  href: guide/index.md
+  href: guides/
 
-- name: Configuration and settings
-  href: configuration/index.md
+- name: Configuration
+  href: configuration/
 
-- name: Samples
+- name: Integrations
+  href: integrations/
+
+- name: Samples (external)
   href: https://github.com/openiddict/openiddict-samples
 
-- name: Changelog
+- name: Changelog (external)
   href: https://github.com/openiddict/openiddict-core/releases
\ No newline at end of file