diff --git a/common/changes/@microsoft/tsdoc-config/synonyms_2019-12-19-22-47.json b/common/changes/@microsoft/tsdoc-config/synonyms_2019-12-19-22-47.json
new file mode 100644
index 00000000..80673684
--- /dev/null
+++ b/common/changes/@microsoft/tsdoc-config/synonyms_2019-12-19-22-47.json
@@ -0,0 +1,11 @@
+{
+  "changes": [
+    {
+      "packageName": "@microsoft/tsdoc-config",
+      "comment": "Add support for configuring synonyms.",
+      "type": "minor"
+    }
+  ],
+  "packageName": "@microsoft/tsdoc-config",
+  "email": "ron.buckton@microsoft.com"
+}
\ No newline at end of file
diff --git a/common/changes/@microsoft/tsdoc/synonyms_2019-12-19-22-47.json b/common/changes/@microsoft/tsdoc/synonyms_2019-12-19-22-47.json
new file mode 100644
index 00000000..a057a4c4
--- /dev/null
+++ b/common/changes/@microsoft/tsdoc/synonyms_2019-12-19-22-47.json
@@ -0,0 +1,11 @@
+{
+  "changes": [
+    {
+      "packageName": "@microsoft/tsdoc",
+      "comment": "Add support for synonyms and the 'see' tag.",
+      "type": "minor"
+    }
+  ],
+  "packageName": "@microsoft/tsdoc",
+  "email": "ron.buckton@microsoft.com"
+}
\ No newline at end of file
diff --git a/common/changes/eslint-plugin-tsdoc/synonyms_2019-12-19-22-47.json b/common/changes/eslint-plugin-tsdoc/synonyms_2019-12-19-22-47.json
new file mode 100644
index 00000000..bfab3c9a
--- /dev/null
+++ b/common/changes/eslint-plugin-tsdoc/synonyms_2019-12-19-22-47.json
@@ -0,0 +1,11 @@
+{
+  "changes": [
+    {
+      "packageName": "eslint-plugin-tsdoc",
+      "comment": "",
+      "type": "none"
+    }
+  ],
+  "packageName": "eslint-plugin-tsdoc",
+  "email": "ron.buckton@microsoft.com"
+}
\ No newline at end of file
diff --git a/tsdoc-config/src/TSDocConfigFile.ts b/tsdoc-config/src/TSDocConfigFile.ts
index b65cd25c..76cbd422 100644
--- a/tsdoc-config/src/TSDocConfigFile.ts
+++ b/tsdoc-config/src/TSDocConfigFile.ts
@@ -32,6 +32,16 @@ interface ITagConfigJson {
   tagName: string;
   syntaxKind: 'inline' | 'block' | 'modifier';
   allowMultiple?: boolean;
+  synonyms?: string[];
+}
+
+interface ISynonymConfigJson {
+  add?: ISynonymSetJson;
+  remove?: ISynonymSetJson;
+}
+
+interface ISynonymSetJson {
+  [tagName: string]: string[];
 }
 
 interface IConfigJson {
@@ -39,6 +49,7 @@ interface IConfigJson {
   tsdocVersion: string;
   extends?: string[];
   tagDefinitions: ITagConfigJson[];
+  synonyms?: ISynonymConfigJson;
 }
 
 /**
@@ -64,6 +75,8 @@ export class TSDocConfigFile {
   private _tsdocSchema: string;
   private readonly _extendsPaths: string[];
   private readonly _tagDefinitions: TSDocTagDefinition[];
+  private readonly _synonymAdditions: Map<string, string[]>;
+  private readonly _synonymDeletions: Map<string, string[]>;
 
   private constructor() {
     this.log = new ParserMessageLog();
@@ -75,7 +88,9 @@ export class TSDocConfigFile {
     this._fileMTime = 0;
     this._tsdocSchema = '';
     this._extendsPaths = [];
-    this._tagDefinitions= [];
+    this._tagDefinitions = [];
+    this._synonymAdditions = new Map<string, string[]>();
+    this._synonymDeletions = new Map<string, string[]>();
   }
 
   /**
@@ -132,6 +147,14 @@ export class TSDocConfigFile {
     return this._tagDefinitions;
   }
 
+  public get synonymAdditions(): ReadonlyMap<string, ReadonlyArray<string>> {
+    return this._synonymAdditions;
+  }
+
+  public get synonymDeletions(): ReadonlyMap<string, ReadonlyArray<string>> {
+    return this._synonymDeletions;
+  }
+
   /**
    * This can be used for cache eviction.  It returns true if the modification timestamp has changed for
    * any of the files that were read when loading this `TSDocConfigFile`, which indicates that the file should be
@@ -227,9 +250,22 @@ export class TSDocConfigFile {
       this._tagDefinitions.push(new TSDocTagDefinition({
         tagName: jsonTagDefinition.tagName,
         syntaxKind: syntaxKind,
+        synonyms: jsonTagDefinition.synonyms,
         allowMultiple: jsonTagDefinition.allowMultiple
       }));
     }
+    if (configJson.synonyms) {
+      if (configJson.synonyms.add) {
+        for (const tagName of Object.keys(configJson.synonyms.add)) {
+          this._synonymAdditions.set(tagName, configJson.synonyms.add[tagName]);
+        }
+      }
+      if (configJson.synonyms.remove) {
+        for (const tagName of Object.keys(configJson.synonyms.remove)) {
+          this._synonymDeletions.set(tagName, configJson.synonyms.remove[tagName]);
+        }
+      }
+    }
   }
 
   private _loadWithExtends(configFilePath: string, referencingConfigFile: TSDocConfigFile | undefined,
@@ -388,5 +424,23 @@ export class TSDocConfigFile {
     for (const tagDefinition of this.tagDefinitions) {
       configuration.addTagDefinition(tagDefinition);
     }
+
+    this.synonymDeletions.forEach((synonyms, tagName) => {
+      const tagDefinition: TSDocTagDefinition | undefined
+        = configuration.tryGetTagDefinition(tagName);
+      if (!tagDefinition) {
+        throw new Error(`A tag with the name ${tagName} could not be found.`);
+      }
+      configuration.removeSynonym(tagDefinition, ...synonyms);
+    });
+
+    this.synonymAdditions.forEach((synonyms, tagName) => {
+      const tagDefinition: TSDocTagDefinition | undefined
+        = configuration.tryGetTagDefinition(tagName);
+      if (!tagDefinition) {
+        throw new Error(`A tag with the name ${tagName} could not be found.`);
+      }
+      configuration.addSynonym(tagDefinition, ...synonyms);
+    });
   }
 }
diff --git a/tsdoc-config/src/__tests__/TSDocConfigFile.test.ts b/tsdoc-config/src/__tests__/TSDocConfigFile.test.ts
index 8e0af966..408e24ac 100644
--- a/tsdoc-config/src/__tests__/TSDocConfigFile.test.ts
+++ b/tsdoc-config/src/__tests__/TSDocConfigFile.test.ts
@@ -1,6 +1,7 @@
 import * as path from 'path';
 
 import { TSDocConfigFile } from '../TSDocConfigFile';
+import { TSDocSynonymCollection } from '@microsoft/tsdoc/lib/configuration/TSDocSynonymCollection';
 
 function getRelativePath(testPath: string): string {
   return path
@@ -23,10 +24,32 @@ expect.addSnapshotSerializer({
       extendsPaths: value.extendsPaths,
       extendsFiles: value.extendsFiles,
       tagDefinitions: value.tagDefinitions,
+      synonymAdditions: Array.from(value.synonymAdditions).reduce<Record<string, ReadonlyArray<string>>>(
+        (obj, [key, value]) => {
+          obj[key] = value;
+          return obj;
+        },
+        {}
+      ),
+      synonymDeletions: Array.from(value.synonymDeletions).reduce<Record<string, ReadonlyArray<string>>>(
+        (obj, [key, value]) => {
+          obj[key] = value;
+          return obj;
+        },
+        {}
+      ),
       messages: value.log.messages
     });
   }
 });
+expect.addSnapshotSerializer({
+  test(value: unknown) {
+    return value instanceof TSDocSynonymCollection;
+  },
+  print(value: TSDocSynonymCollection, serialize: (value: unknown) => string, indent: (str: string) => string): string {
+    return serialize(value.synonyms);
+  }
+});
 
 function testLoadingFolder(assetPath: string): TSDocConfigFile {
   return TSDocConfigFile.loadForFolder(path.join(__dirname, assetPath));
@@ -40,6 +63,8 @@ test('Load p1', () => {
       "fileNotFound": false,
       "filePath": "assets/p1/tsdoc.json",
       "messages": Array [],
+      "synonymAdditions": Object {},
+      "synonymDeletions": Object {},
       "tagDefinitions": Array [],
       "tsdocSchema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
     }
@@ -66,6 +91,8 @@ test('Load p2', () => {
           "unformattedText": "File not found",
         },
       ],
+      "synonymAdditions": Object {},
+      "synonymDeletions": Object {},
       "tagDefinitions": Array [],
       "tsdocSchema": "",
     }
@@ -81,8 +108,11 @@ test('Load p3', () => {
           "fileNotFound": false,
           "filePath": "assets/p3/base1/tsdoc-base1.json",
           "messages": Array [],
+          "synonymAdditions": Object {},
+          "synonymDeletions": Object {},
           "tagDefinitions": Array [
             TSDocTagDefinition {
+              "_synonymCollection": Array [],
               "allowMultiple": false,
               "standardization": "None",
               "syntaxKind": 2,
@@ -98,8 +128,11 @@ test('Load p3', () => {
           "fileNotFound": false,
           "filePath": "assets/p3/base2/tsdoc-base2.json",
           "messages": Array [],
+          "synonymAdditions": Object {},
+          "synonymDeletions": Object {},
           "tagDefinitions": Array [
             TSDocTagDefinition {
+              "_synonymCollection": Array [],
               "allowMultiple": false,
               "standardization": "None",
               "syntaxKind": 2,
@@ -117,8 +150,11 @@ test('Load p3', () => {
       "fileNotFound": false,
       "filePath": "assets/p3/tsdoc.json",
       "messages": Array [],
+      "synonymAdditions": Object {},
+      "synonymDeletions": Object {},
       "tagDefinitions": Array [
         TSDocTagDefinition {
+          "_synonymCollection": Array [],
           "allowMultiple": false,
           "standardization": "None",
           "syntaxKind": 2,
@@ -140,8 +176,11 @@ test('Load p4', () => {
           "fileNotFound": false,
           "filePath": "assets/p4/node_modules/example-lib/dist/tsdoc-example.json",
           "messages": Array [],
+          "synonymAdditions": Object {},
+          "synonymDeletions": Object {},
           "tagDefinitions": Array [
             TSDocTagDefinition {
+              "_synonymCollection": Array [],
               "allowMultiple": false,
               "standardization": "None",
               "syntaxKind": 2,
@@ -158,8 +197,11 @@ test('Load p4', () => {
       "fileNotFound": false,
       "filePath": "assets/p4/tsdoc.json",
       "messages": Array [],
+      "synonymAdditions": Object {},
+      "synonymDeletions": Object {},
       "tagDefinitions": Array [
         TSDocTagDefinition {
+          "_synonymCollection": Array [],
           "allowMultiple": false,
           "standardization": "None",
           "syntaxKind": 2,
@@ -171,3 +213,33 @@ test('Load p4', () => {
     }
   `);
 });
+test('Load synonyms', () => {
+  expect(testLoadingFolder('assets/synonyms')).toMatchInlineSnapshot(`
+    Object {
+      "extendsFiles": Array [],
+      "extendsPaths": Array [],
+      "fileNotFound": false,
+      "filePath": "assets/synonyms/tsdoc.json",
+      "messages": Array [],
+      "synonymAdditions": Object {
+        "@readonly": Array [
+          "@readonly2",
+        ],
+      },
+      "synonymDeletions": Object {},
+      "tagDefinitions": Array [
+        TSDocTagDefinition {
+          "_synonymCollection": Array [
+            "@bar",
+          ],
+          "allowMultiple": false,
+          "standardization": "None",
+          "syntaxKind": 1,
+          "tagName": "@foo",
+          "tagNameWithUpperCase": "@FOO",
+        },
+      ],
+      "tsdocSchema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
+    }
+  `);
+});
diff --git a/tsdoc-config/src/__tests__/assets/synonyms/tsconfig.json b/tsdoc-config/src/__tests__/assets/synonyms/tsconfig.json
new file mode 100644
index 00000000..2c63c085
--- /dev/null
+++ b/tsdoc-config/src/__tests__/assets/synonyms/tsconfig.json
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tsdoc-config/src/__tests__/assets/synonyms/tsdoc.json b/tsdoc-config/src/__tests__/assets/synonyms/tsdoc.json
new file mode 100644
index 00000000..0d48f74e
--- /dev/null
+++ b/tsdoc-config/src/__tests__/assets/synonyms/tsdoc.json
@@ -0,0 +1,11 @@
+{
+    "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
+    "tagDefinitions": [
+        { "tagName": "@foo", "syntaxKind": "block", "synonyms": ["@bar"] }
+    ],
+    "synonyms": {
+        "add": {
+            "@readonly": ["@readonly2"]
+        }
+    }
+}
\ No newline at end of file
diff --git a/tsdoc/schemas/tsdoc.schema.json b/tsdoc/schemas/tsdoc.schema.json
index bfb9b425..c9158034 100644
--- a/tsdoc/schemas/tsdoc.schema.json
+++ b/tsdoc/schemas/tsdoc.schema.json
@@ -22,6 +22,22 @@
       "items": {
         "$ref": "#/definitions/tsdocTagDefinition"
       }
+    },
+    
+    "synonyms": {
+      "description": "Additional synonyms to add or remove from built-in tag definitions.",
+      "type": "object",
+      "properties": {
+        "add": {
+          "description": "Synonyms to add.",
+          "$ref": "#/definitions/synonymSet"
+        },
+        "remove": {
+          "description": "Synonyms to remove.",
+          "$ref": "#/definitions/synonymSet"
+        }
+      },
+      "additionalProperties": false
     }
   },
   "required": [ "$schema" ],
@@ -44,10 +60,28 @@
         "allowMultiple": {
           "description": "If true, then this tag may appear multiple times in a doc comment. By default, a tag may only appear once.",
           "type": "boolean"
+        },
+        "synonyms": {
+          "description": "Synonyms of the custom tag. TSDoc tag names start with an at-sign (@) followed by ASCII letters using camelCase capitalization.",
+          "type": "array",
+          "items": {
+            "type": "string"
+          }
         }
       },
       "required": ["tagName", "syntaxKind"],
       "additionalProperties": false
+    },
+    "synonymSet": {
+      "description": "Provides the assocation between a tag and the synonyms to be added or removed.",
+      "type": "object",
+      "additionalProperties": {
+        "description": "Synonyms of the tag. TSDoc tag names start with an at-sign (@) followed by ASCII letters using camelCase capitalization.",
+        "type": "array",
+        "items": {
+          "type": "string"
+        }
+      }
     }
   }
 }
diff --git a/tsdoc/src/__tests__/ParsingBasics.test.ts b/tsdoc/src/__tests__/ParsingBasics.test.ts
index 407593f5..fd4d326c 100644
--- a/tsdoc/src/__tests__/ParsingBasics.test.ts
+++ b/tsdoc/src/__tests__/ParsingBasics.test.ts
@@ -7,6 +7,7 @@ import {
   TSDocTagSyntaxKind
 } from '../index';
 import { TestHelpers } from '../parser/__tests__/TestHelpers';
+import { StandardTags } from '../details/StandardTags';
 
 test('01 Simple @beta and @internal extraction', () => {
   const parserContext: ParserContext = TestHelpers.parseAndMatchDocCommentSnapshot([
@@ -157,4 +158,18 @@ test('07 Invalid JSDoc type', () => {
     ' * @public',
     ' */'
   ].join('\n'));
+});
+
+test('08 synonyms', () => {
+  const configuration: TSDocConfiguration = new TSDocConfiguration();
+  configuration.addSynonym(StandardTags.readonly, "@readonly2");
+  TestHelpers.parseAndMatchDocCommentSnapshot([
+    '/**',
+    ' * @param a - description1',
+    ' * @arg b - description2',
+    ' * @argument c - description3',
+    ' * @return description4',
+    ' * @readonly2',
+    ' */'
+  ].join('\n'), configuration);
 });
\ No newline at end of file
diff --git a/tsdoc/src/__tests__/__snapshots__/ParsingBasics.test.ts.snap b/tsdoc/src/__tests__/__snapshots__/ParsingBasics.test.ts.snap
index 55e2f069..dac42056 100644
--- a/tsdoc/src/__tests__/__snapshots__/ParsingBasics.test.ts.snap
+++ b/tsdoc/src/__tests__/__snapshots__/ParsingBasics.test.ts.snap
@@ -3002,3 +3002,276 @@ Object {
   ],
 }
 `;
+
+exports[`08 synonyms 1`] = `
+Object {
+  "_00_lines": Array [
+    "@param a - description1",
+    "@arg b - description2",
+    "@argument c - description3",
+    "@return description4",
+    "@readonly2",
+  ],
+  "_01_gaps": Array [],
+  "_02_summarySection": Object {
+    "kind": "Section",
+  },
+  "_03_remarksBlock": undefined,
+  "_04_privateRemarksBlock": undefined,
+  "_05_deprecatedBlock": undefined,
+  "_06_paramBlocks": Array [
+    Object {
+      "kind": "ParamBlock",
+      "nodes": Array [
+        Object {
+          "kind": "BlockTag",
+          "nodes": Array [
+            Object {
+              "kind": "Excerpt: BlockTag",
+              "nodeExcerpt": "@param",
+            },
+          ],
+        },
+        Object {
+          "kind": "Excerpt: Spacing",
+          "nodeExcerpt": " ",
+        },
+        Object {
+          "kind": "Excerpt: ParamBlock_ParameterName",
+          "nodeExcerpt": "a",
+        },
+        Object {
+          "kind": "Excerpt: Spacing",
+          "nodeExcerpt": " ",
+        },
+        Object {
+          "kind": "Excerpt: ParamBlock_Hyphen",
+          "nodeExcerpt": "-",
+        },
+        Object {
+          "kind": "Excerpt: Spacing",
+          "nodeExcerpt": " ",
+        },
+        Object {
+          "kind": "Section",
+          "nodes": Array [
+            Object {
+              "kind": "Paragraph",
+              "nodes": Array [
+                Object {
+                  "kind": "PlainText",
+                  "nodes": Array [
+                    Object {
+                      "kind": "Excerpt: PlainText",
+                      "nodeExcerpt": "description1",
+                    },
+                  ],
+                },
+                Object {
+                  "kind": "SoftBreak",
+                  "nodes": Array [
+                    Object {
+                      "kind": "Excerpt: SoftBreak",
+                      "nodeExcerpt": "[n]",
+                    },
+                  ],
+                },
+              ],
+            },
+          ],
+        },
+      ],
+    },
+    Object {
+      "kind": "ParamBlock",
+      "nodes": Array [
+        Object {
+          "kind": "BlockTag",
+          "nodes": Array [
+            Object {
+              "kind": "Excerpt: BlockTag",
+              "nodeExcerpt": "@arg",
+            },
+          ],
+        },
+        Object {
+          "kind": "Excerpt: Spacing",
+          "nodeExcerpt": " ",
+        },
+        Object {
+          "kind": "Excerpt: ParamBlock_ParameterName",
+          "nodeExcerpt": "b",
+        },
+        Object {
+          "kind": "Excerpt: Spacing",
+          "nodeExcerpt": " ",
+        },
+        Object {
+          "kind": "Excerpt: ParamBlock_Hyphen",
+          "nodeExcerpt": "-",
+        },
+        Object {
+          "kind": "Excerpt: Spacing",
+          "nodeExcerpt": " ",
+        },
+        Object {
+          "kind": "Section",
+          "nodes": Array [
+            Object {
+              "kind": "Paragraph",
+              "nodes": Array [
+                Object {
+                  "kind": "PlainText",
+                  "nodes": Array [
+                    Object {
+                      "kind": "Excerpt: PlainText",
+                      "nodeExcerpt": "description2",
+                    },
+                  ],
+                },
+                Object {
+                  "kind": "SoftBreak",
+                  "nodes": Array [
+                    Object {
+                      "kind": "Excerpt: SoftBreak",
+                      "nodeExcerpt": "[n]",
+                    },
+                  ],
+                },
+              ],
+            },
+          ],
+        },
+      ],
+    },
+    Object {
+      "kind": "ParamBlock",
+      "nodes": Array [
+        Object {
+          "kind": "BlockTag",
+          "nodes": Array [
+            Object {
+              "kind": "Excerpt: BlockTag",
+              "nodeExcerpt": "@argument",
+            },
+          ],
+        },
+        Object {
+          "kind": "Excerpt: Spacing",
+          "nodeExcerpt": " ",
+        },
+        Object {
+          "kind": "Excerpt: ParamBlock_ParameterName",
+          "nodeExcerpt": "c",
+        },
+        Object {
+          "kind": "Excerpt: Spacing",
+          "nodeExcerpt": " ",
+        },
+        Object {
+          "kind": "Excerpt: ParamBlock_Hyphen",
+          "nodeExcerpt": "-",
+        },
+        Object {
+          "kind": "Excerpt: Spacing",
+          "nodeExcerpt": " ",
+        },
+        Object {
+          "kind": "Section",
+          "nodes": Array [
+            Object {
+              "kind": "Paragraph",
+              "nodes": Array [
+                Object {
+                  "kind": "PlainText",
+                  "nodes": Array [
+                    Object {
+                      "kind": "Excerpt: PlainText",
+                      "nodeExcerpt": "description3",
+                    },
+                  ],
+                },
+                Object {
+                  "kind": "SoftBreak",
+                  "nodes": Array [
+                    Object {
+                      "kind": "Excerpt: SoftBreak",
+                      "nodeExcerpt": "[n]",
+                    },
+                  ],
+                },
+              ],
+            },
+          ],
+        },
+      ],
+    },
+  ],
+  "_07_typeParamBlocks": Array [],
+  "_08_returnsBlock": Object {
+    "kind": "Block",
+    "nodes": Array [
+      Object {
+        "kind": "BlockTag",
+        "nodes": Array [
+          Object {
+            "kind": "Excerpt: BlockTag",
+            "nodeExcerpt": "@return",
+          },
+        ],
+      },
+      Object {
+        "kind": "Section",
+        "nodes": Array [
+          Object {
+            "kind": "Paragraph",
+            "nodes": Array [
+              Object {
+                "kind": "PlainText",
+                "nodes": Array [
+                  Object {
+                    "kind": "Excerpt: PlainText",
+                    "nodeExcerpt": " description4",
+                  },
+                ],
+              },
+              Object {
+                "kind": "SoftBreak",
+                "nodes": Array [
+                  Object {
+                    "kind": "Excerpt: SoftBreak",
+                    "nodeExcerpt": "[n]",
+                  },
+                ],
+              },
+              Object {
+                "kind": "SoftBreak",
+                "nodes": Array [
+                  Object {
+                    "kind": "Excerpt: SoftBreak",
+                    "nodeExcerpt": "[n]",
+                  },
+                ],
+              },
+            ],
+          },
+        ],
+      },
+    ],
+  },
+  "_09_customBlocks": Array [],
+  "_10_inheritDocTag": undefined,
+  "_11_modifierTags": Array [
+    Object {
+      "kind": "BlockTag",
+      "nodes": Array [
+        Object {
+          "kind": "Excerpt: BlockTag",
+          "nodeExcerpt": "@readonly2",
+        },
+      ],
+    },
+  ],
+  "_12_logMessages": Array [],
+}
+`;
diff --git a/tsdoc/src/configuration/TSDocConfiguration.ts b/tsdoc/src/configuration/TSDocConfiguration.ts
index abd08a57..290c246d 100644
--- a/tsdoc/src/configuration/TSDocConfiguration.ts
+++ b/tsdoc/src/configuration/TSDocConfiguration.ts
@@ -1,24 +1,35 @@
 import { StandardTags } from '../details/StandardTags';
-import { TSDocTagDefinition } from './TSDocTagDefinition';
+import { TSDocTagDefinition, ITSDocTagDefinitionInternalParameters } from './TSDocTagDefinition';
 import { TSDocValidationConfiguration } from './TSDocValidationConfiguration';
 import { DocNodeManager } from './DocNodeManager';
 import { BuiltInDocNodes } from '../nodes/BuiltInDocNodes';
 import { TSDocMessageId, allTsdocMessageIds, allTsdocMessageIdsSet } from '../parser/TSDocMessageId';
+import { TSDocSynonymCollection } from './TSDocSynonymCollection';
+import { StringChecks } from '../parser/StringChecks';
+
+interface ITSDocTagDefinitionOverride {
+  derivedTagDefinition: TSDocTagDefinition;
+  synonymCollection: TSDocSynonymCollection;
+}
 
 /**
  * Configuration for the TSDocParser.
  */
 export class TSDocConfiguration {
-  private readonly _tagDefinitions: TSDocTagDefinition[];
-  private readonly _tagDefinitionsByName: Map<string, TSDocTagDefinition>;
-  private readonly _supportedTagDefinitions: Set<TSDocTagDefinition>;
+  private readonly _baseTagDefinitionsByName: Map<string, TSDocTagDefinition>;
+  private readonly _baseTagDefinitions: TSDocTagDefinition[];
+  private readonly _supportedBaseTagDefinitions: Set<TSDocTagDefinition>;
   private readonly _validation: TSDocValidationConfiguration;
   private readonly _docNodeManager: DocNodeManager;
+  private _tagDefinitionOverrides: Map<TSDocTagDefinition, ITSDocTagDefinitionOverride> | undefined;
+  private _tagDefinitionOverridesReverseMap: Map<TSDocTagDefinition, TSDocTagDefinition> | undefined;
+  private _derivedTagDefinitions: TSDocTagDefinition[] | undefined;
+  private _supportedDerivedTagDefinitions: TSDocTagDefinition[] | undefined;
 
   public constructor() {
-    this._tagDefinitions = [];
-    this._tagDefinitionsByName = new Map<string, TSDocTagDefinition>();
-    this._supportedTagDefinitions = new Set<TSDocTagDefinition>();
+    this._baseTagDefinitions = [];
+    this._baseTagDefinitionsByName = new Map<string, TSDocTagDefinition>();
+    this._supportedBaseTagDefinitions = new Set<TSDocTagDefinition>();
     this._validation = new TSDocValidationConfiguration();
     this._docNodeManager = new DocNodeManager();
 
@@ -36,7 +47,10 @@ export class TSDocConfiguration {
    * The subset of "supported" tags is tracked by {@link TSDocConfiguration.supportedTagDefinitions}.
    */
   public get tagDefinitions(): ReadonlyArray<TSDocTagDefinition> {
-    return this._tagDefinitions;
+    if (!this._derivedTagDefinitions) {
+      this._derivedTagDefinitions = this._baseTagDefinitions.map(tagDefinition => this.getConfiguredTagDefinition(tagDefinition));
+    }
+    return this._derivedTagDefinitions;
   }
 
   /**
@@ -48,7 +62,10 @@ export class TSDocConfiguration {
    * {@link TSDocValidationConfiguration.reportUnsupportedTags} is enabled.
    */
   public get supportedTagDefinitions(): ReadonlyArray<TSDocTagDefinition> {
-    return this.tagDefinitions.filter(x => this.isTagSupported(x));
+    if (!this._supportedDerivedTagDefinitions) {
+      this._supportedDerivedTagDefinitions = this.tagDefinitions.filter(x => this.isTagSupported(x));
+    }
+    return this._supportedDerivedTagDefinitions;
   }
 
   /**
@@ -70,7 +87,7 @@ export class TSDocConfiguration {
    * if not found.
    */
   public tryGetTagDefinition(tagName: string): TSDocTagDefinition | undefined {
-    return this._tagDefinitionsByName.get(tagName.toUpperCase());
+    return this.tryGetTagDefinitionWithUpperCase(tagName.toUpperCase());
   }
 
   /**
@@ -78,7 +95,19 @@ export class TSDocConfiguration {
    * if not found.
    */
   public tryGetTagDefinitionWithUpperCase(alreadyUpperCaseTagName: string): TSDocTagDefinition | undefined {
-    return this._tagDefinitionsByName.get(alreadyUpperCaseTagName);
+    const tagDefinition: TSDocTagDefinition | undefined
+      = this._baseTagDefinitionsByName.get(alreadyUpperCaseTagName);
+    return tagDefinition && this.getConfiguredTagDefinition(tagDefinition);
+  }
+
+  /**
+   * Return the configured version of a tag definition. If a tag definition has been configured
+   * with additional synonyms, the derived tag definition is returned.
+   */
+  public getConfiguredTagDefinition(tagDefinition: TSDocTagDefinition): TSDocTagDefinition {
+    const override: ITSDocTagDefinitionOverride | undefined =
+      this._tagDefinitionOverrides && this._tagDefinitionOverrides.get(tagDefinition);
+    return override ? override.derivedTagDefinition : tagDefinition;
   }
 
   /**
@@ -89,20 +118,11 @@ export class TSDocConfiguration {
    * If a tag is "defined" this means that the parser recognizes it and understands its syntax.
    * Whereas if a tag is "supported", this means it is defined AND the application implements the tag.
    */
-  public addTagDefinition(tagDefinition: TSDocTagDefinition): void {
-    const existingDefinition: TSDocTagDefinition | undefined
-      = this._tagDefinitionsByName.get(tagDefinition.tagNameWithUpperCase);
-
-    if (existingDefinition === tagDefinition) {
-      return;
-    }
-
-    if (existingDefinition) {
-      throw new Error(`A tag is already defined using the name ${existingDefinition.tagName}`);
+  public addTagDefinition(tagDefinition: TSDocTagDefinition, supported?: boolean | undefined): void {
+    this._addTagDefinition(tagDefinition);
+    if (supported !== undefined) {
+      this.setSupportForTag(tagDefinition, supported);
     }
-
-    this._tagDefinitions.push(tagDefinition);
-    this._tagDefinitionsByName.set(tagDefinition.tagNameWithUpperCase, tagDefinition);
   }
 
   /**
@@ -116,11 +136,7 @@ export class TSDocConfiguration {
     supported?: boolean | undefined): void {
 
     for (const tagDefinition of tagDefinitions) {
-      this.addTagDefinition(tagDefinition);
-
-      if (supported !== undefined) {
-        this.setSupportForTag(tagDefinition, supported);
-      }
+      this.addTagDefinition(tagDefinition, supported);
     }
   }
 
@@ -128,8 +144,9 @@ export class TSDocConfiguration {
    * Returns true if the tag is supported in this configuration.
    */
   public isTagSupported(tagDefinition: TSDocTagDefinition): boolean {
-    this._requireTagToBeDefined(tagDefinition);
-    return this._supportedTagDefinitions.has(tagDefinition);
+    const baseTagDefinition: TSDocTagDefinition = this._getBaseTagDefinition(tagDefinition);
+    this._requireTagToBeDefined(baseTagDefinition);
+    return this._supportedBaseTagDefinitions.has(baseTagDefinition);
   }
 
   /**
@@ -144,14 +161,16 @@ export class TSDocConfiguration {
    * to true.
    */
   public setSupportForTag(tagDefinition: TSDocTagDefinition, supported: boolean): void {
-    this._requireTagToBeDefined(tagDefinition);
+    const baseTagDefinition: TSDocTagDefinition = this._getBaseTagDefinition(tagDefinition);
+    this._requireTagToBeDefined(baseTagDefinition);
     if (supported) {
-      this._supportedTagDefinitions.add(tagDefinition);
+      this._supportedBaseTagDefinitions.add(baseTagDefinition);
     } else {
-      this._supportedTagDefinitions.delete(tagDefinition);
+      this._supportedBaseTagDefinitions.delete(baseTagDefinition);
     }
 
     this.validation.reportUnsupportedTags = true;
+    this._invalidateDerived();
   }
 
   /**
@@ -163,6 +182,101 @@ export class TSDocConfiguration {
     }
   }
 
+  /**
+   * Adds a synonym to a registered tag definition.
+   * @param tagDefinition - The tag definition to which to add a new synonym.
+   * @param synonyms - The synonyms to add.
+   * @returns The configured version of the provided tag definition.
+   */
+  public addSynonym(tagDefinition: TSDocTagDefinition, ...synonyms: string[]): TSDocTagDefinition {
+    const baseTagDefinition: TSDocTagDefinition = this._getBaseTagDefinition(tagDefinition);
+    this._requireTagToBeDefined(baseTagDefinition);
+
+    const synonymsWithUpperCase: string[] = synonyms.map(synonym => synonym.toUpperCase());
+    const synonymsToAdd: string[] = [];
+    const synonymsWithUpperCaseToAdd: string[] = [];
+    for (let i: number = 0; i < synonyms.length; i++) {
+      const synonym: string = synonyms[i];
+      const synonymWithUpperCase: string = synonymsWithUpperCase[i];
+      StringChecks.validateTSDocTagName(synonym);
+      
+      const existingDefinition: TSDocTagDefinition | undefined
+        = this._baseTagDefinitionsByName.get(synonymWithUpperCase);
+
+      if (existingDefinition) {
+        if (existingDefinition !== baseTagDefinition) {
+          throw new Error(`A tag is already defined using the name ${synonym}`);
+        }
+        continue;
+      }
+
+      synonymsToAdd.push(synonym);
+      synonymsWithUpperCaseToAdd.push(synonymWithUpperCase);
+    }
+
+    if (synonymsToAdd.length === 0) {
+      return this.getConfiguredTagDefinition(baseTagDefinition);
+    }
+
+    const override: ITSDocTagDefinitionOverride = this._overrideTagDefinition(baseTagDefinition);
+    for (let i: number = 0; i < synonymsToAdd.length; i++) {
+      override.synonymCollection.add(synonymsToAdd[i]);
+      this._baseTagDefinitionsByName.set(synonymsWithUpperCaseToAdd[i], baseTagDefinition);
+    }
+
+    return override.derivedTagDefinition;
+  }
+
+  /**
+   * Removes a synonym from a registered tag definition.
+   * @param tagDefinition - The tag definition from which to remove a synonym.
+   * @param synonyms - The synonyms to remove.
+   * @returns The configured version of the provided tag definition.
+   */
+  public removeSynonym(tagDefinition: TSDocTagDefinition, ...synonyms: string[]): TSDocTagDefinition {
+    const baseTagDefinition: TSDocTagDefinition = this._getBaseTagDefinition(tagDefinition);
+    this._requireTagToBeDefined(baseTagDefinition);
+
+    const synonymsWithUpperCase: string[] = synonyms.map(synonym => synonym.toUpperCase());
+    const synonymsToRemove: string[] = [];
+    const synonymsWithUpperCaseToRemove: string[] = [];
+    for (let i: number = 0; i < synonyms.length; i++) {
+      const synonym: string = synonyms[i];
+      const synonymWithUpperCase: string = synonymsWithUpperCase[i];
+      StringChecks.validateTSDocTagName(synonym);
+      
+      const existingDefinition: TSDocTagDefinition | undefined
+        = this._baseTagDefinitionsByName.get(synonymWithUpperCase);
+
+      if (!existingDefinition) {
+        continue;
+      }
+
+      if (existingDefinition !== baseTagDefinition) {
+        throw new Error(`The synonym ${synonym} is not provided by this tag.`);
+      }
+
+      if (baseTagDefinition.tagNameWithUpperCase === synonymWithUpperCase) {
+        throw new Error(`${synonym} is the primary tag name for this definition and cannot be removed.`);
+      }
+  
+      synonymsToRemove.push(synonym);
+      synonymsWithUpperCaseToRemove.push(synonymWithUpperCase);
+    }
+
+    if (synonymsToRemove.length === 0) {
+      return this.getConfiguredTagDefinition(baseTagDefinition);
+    }
+    
+    const override: ITSDocTagDefinitionOverride = this._overrideTagDefinition(baseTagDefinition);
+    for (let i: number = 0; i < synonymsToRemove.length; i++) {
+      override.synonymCollection.delete(synonymsToRemove[i]);
+      this._baseTagDefinitionsByName.delete(synonymsWithUpperCaseToRemove[i]);
+    }
+
+    return override.derivedTagDefinition;
+  }
+
   /**
    * Returns true if the specified {@link TSDocMessageId} string is implemented by this release of the TSDoc parser.
    * This can be used to detect misspelled identifiers.
@@ -188,14 +302,99 @@ export class TSDocConfiguration {
     return allTsdocMessageIds as ReadonlyArray<TSDocMessageId>;
   }
 
-  private _requireTagToBeDefined(tagDefinition: TSDocTagDefinition): void {
+  private _requireTagToBeDefined(baseTagDefinition: TSDocTagDefinition): void {
     const matching: TSDocTagDefinition | undefined
-      = this._tagDefinitionsByName.get(tagDefinition.tagNameWithUpperCase);
+      = this._baseTagDefinitionsByName.get(baseTagDefinition.tagNameWithUpperCase);
     if (matching) {
-      if (matching === tagDefinition) {
+      if (matching === baseTagDefinition) {
         return;
       }
     }
     throw new Error('The specified TSDocTagDefinition is not defined for this TSDocConfiguration');
   }
+
+  private _getBaseTagDefinition(tagDefinition: TSDocTagDefinition): TSDocTagDefinition {
+    return this._tagDefinitionOverridesReverseMap &&
+      this._tagDefinitionOverridesReverseMap.get(tagDefinition) || tagDefinition;
+  }
+
+  private _addTagDefinition(tagDefinition: TSDocTagDefinition): void {
+    const baseTagDefinition: TSDocTagDefinition = this._getBaseTagDefinition(tagDefinition);
+    const existingDefinition: TSDocTagDefinition | undefined
+      = this._baseTagDefinitionsByName.get(baseTagDefinition.tagNameWithUpperCase);
+
+    if (existingDefinition === baseTagDefinition) {
+      return;
+    }
+
+    if (existingDefinition) {
+      throw new Error(`A tag is already defined using the name ${existingDefinition.tagName}`);
+    }
+
+    const synonyms: ReadonlyArray<string> = baseTagDefinition.synonyms;
+    const synonymsWithUpperCase: ReadonlyArray<string> = baseTagDefinition.synonymsWithUpperCase;
+    const synonymsToAdd: string[] = [];
+    for (let i: number = 0; i < synonymsWithUpperCase.length; i++) {
+      const synonymWithUpperCase: string = synonymsWithUpperCase[i];
+      const existingDefinition: TSDocTagDefinition | undefined
+        = this._baseTagDefinitionsByName.get(synonymWithUpperCase);
+      if (existingDefinition) {
+        if (existingDefinition !== baseTagDefinition) {
+          throw new Error(`A tag is already defined using the name ${synonyms[i]}`);
+        }
+        continue;
+      }
+      synonymsToAdd.push(synonymWithUpperCase);
+    }
+
+    this._baseTagDefinitions.push(baseTagDefinition);
+    this._baseTagDefinitionsByName.set(baseTagDefinition.tagNameWithUpperCase, baseTagDefinition);
+    for (const synonym of synonymsToAdd) {
+      this._baseTagDefinitionsByName.set(synonym, baseTagDefinition);
+    }
+
+    this._invalidateDerived();
+  }
+
+  private _overrideTagDefinition(baseTagDefinition: TSDocTagDefinition): ITSDocTagDefinitionOverride {
+    if (!this._tagDefinitionOverrides) {
+      this._tagDefinitionOverrides = new Map<TSDocTagDefinition, ITSDocTagDefinitionOverride>();
+    }
+    if (!this._tagDefinitionOverridesReverseMap) {
+      this._tagDefinitionOverridesReverseMap = new Map<TSDocTagDefinition, TSDocTagDefinition>();
+    }
+
+    let override: ITSDocTagDefinitionOverride | undefined =
+      this._tagDefinitionOverrides.get(baseTagDefinition);
+
+    if (!override) {
+      const synonymCollection: TSDocSynonymCollection = new TSDocSynonymCollection();
+      const derivedTagParameters: ITSDocTagDefinitionInternalParameters = {
+        tagName: baseTagDefinition.tagName,
+        syntaxKind: baseTagDefinition.syntaxKind,
+        allowMultiple: baseTagDefinition.allowMultiple,
+        standardization: baseTagDefinition.standardization,
+        synonyms: baseTagDefinition.synonyms.slice(),
+        synonymCollection,
+      };
+
+      const derivedTagDefinition: TSDocTagDefinition = new TSDocTagDefinition(derivedTagParameters);
+      override = { derivedTagDefinition, synonymCollection };
+
+      this._tagDefinitionOverrides.set(baseTagDefinition, override);
+      this._tagDefinitionOverridesReverseMap.set(derivedTagDefinition, baseTagDefinition);
+      this._invalidateDerived();
+    }
+
+    return override;
+  }
+
+  private _invalidateDerived(): void {
+    if (this._derivedTagDefinitions) {
+      this._derivedTagDefinitions = undefined;
+    }
+    if (this._supportedDerivedTagDefinitions) {
+      this._supportedDerivedTagDefinitions = undefined;
+    }
+  }
 }
diff --git a/tsdoc/src/configuration/TSDocSynonymCollection.ts b/tsdoc/src/configuration/TSDocSynonymCollection.ts
new file mode 100644
index 00000000..3718fccc
--- /dev/null
+++ b/tsdoc/src/configuration/TSDocSynonymCollection.ts
@@ -0,0 +1,67 @@
+import { StringChecks } from "../parser/StringChecks";
+
+/**
+ * @internal
+ */
+export class TSDocSynonymCollection {
+    private _synonyms: string[];
+    private _synonymsWithUpperCase: string[] | undefined;
+
+    public constructor() {
+        this._synonyms = [];
+        this._synonymsWithUpperCase = undefined;
+    }
+
+    public get count(): number {
+        return this._synonyms.length;
+    }
+
+    public get synonyms(): ReadonlyArray<string> {
+        return this._synonyms;
+    }
+
+    public get synonymsWithUpperCase(): ReadonlyArray<string> {
+        if (!this._synonymsWithUpperCase) {
+            this._synonymsWithUpperCase = this._synonyms.map(synonym => synonym.toUpperCase());
+        }
+        return this._synonymsWithUpperCase;
+    }
+
+    public add(synonym: string): void {
+        StringChecks.validateTSDocTagName(synonym);
+        if (this._synonyms.indexOf(synonym) >= 0) {
+            return;
+        }
+        this._synonyms.push(synonym);
+        this._invalidateSynonymsWithUpperCase();
+    }
+
+    public delete(synonym: string): boolean {
+        const index: number = this._synonyms.indexOf(synonym);
+        if (index >= 0) {
+            this._synonyms.splice(index, 1);
+            this._invalidateSynonymsWithUpperCase();
+            return true;
+        }
+        return false;
+    }
+
+    public clear(): void {
+        this._synonyms.length = 0;
+        this._invalidateSynonymsWithUpperCase();
+    }
+
+    public hasTagName(tagName: string): boolean {
+        return this.synonymsWithUpperCase.indexOf(tagName.toUpperCase()) >= 0;
+    }
+
+    public [Symbol.iterator](): IterableIterator<string> {
+        return this._synonyms[Symbol.iterator]();
+    }
+
+    private _invalidateSynonymsWithUpperCase(): void {
+        if (this._synonymsWithUpperCase) {
+            this._synonymsWithUpperCase = undefined;
+        }
+    }
+}
\ No newline at end of file
diff --git a/tsdoc/src/configuration/TSDocTagDefinition.ts b/tsdoc/src/configuration/TSDocTagDefinition.ts
index 62af44d3..0ec7cae3 100644
--- a/tsdoc/src/configuration/TSDocTagDefinition.ts
+++ b/tsdoc/src/configuration/TSDocTagDefinition.ts
@@ -1,5 +1,7 @@
 import { StringChecks } from '../parser/StringChecks';
 import { Standardization } from '../details/Standardization';
+import { DocBlockTag, DocInlineTagBase } from '../nodes';
+import { TSDocSynonymCollection } from './TSDocSynonymCollection';
 
 /**
  * Determines the type of syntax for a TSDocTagDefinition
@@ -29,6 +31,7 @@ export enum TSDocTagSyntaxKind {
 export interface ITSDocTagDefinitionParameters {
   tagName: string;
   syntaxKind: TSDocTagSyntaxKind;
+  synonyms?: string[];
   allowMultiple?: boolean;
 }
 
@@ -37,6 +40,7 @@ export interface ITSDocTagDefinitionParameters {
  */
 export interface ITSDocTagDefinitionInternalParameters extends ITSDocTagDefinitionParameters {
   standardization: Standardization;
+  synonymCollection?: TSDocSynonymCollection;
 }
 
 /**
@@ -72,6 +76,8 @@ export class TSDocTagDefinition {
    */
   public readonly allowMultiple: boolean;
 
+  private _synonymCollection: TSDocSynonymCollection;
+
   public constructor(parameters: ITSDocTagDefinitionParameters) {
     StringChecks.validateTSDocTagName(parameters.tagName);
     this.tagName = parameters.tagName;
@@ -80,5 +86,49 @@ export class TSDocTagDefinition {
     this.standardization = (parameters as ITSDocTagDefinitionInternalParameters).standardization
       || Standardization.None;
     this.allowMultiple = !!parameters.allowMultiple;
+    this._synonymCollection = (parameters as ITSDocTagDefinitionInternalParameters).synonymCollection ||
+      new TSDocSynonymCollection();
+    if (parameters.synonyms) {
+      for (const synonym of parameters.synonyms) {
+        if (synonym !== this.tagName) {
+          this._synonymCollection.add(synonym);
+        }
+      }
+    }
+  }
+
+  /**
+   * Synonyms for the TSDoc tag.  TSDoc tag names start with an at-sign ("@") followed
+   * by ASCII letters using "camelCase" capitalization.
+   */
+  public get synonyms(): ReadonlyArray<string> {
+    return this._synonymCollection.synonyms;
+  }
+
+  /**
+   * Synonyms for the TSDoc tag in all capitals, which is used for performing
+   * case-insensitive comparisons or lookups.
+   */
+  public get synonymsWithUpperCase(): ReadonlyArray<string> {
+    return this._synonymCollection.synonymsWithUpperCase;
+  }
+
+  /**
+   * Returns whether this tag definition is a definition of the provided tag.
+   */
+  public isDefinitionOfTag(tag: DocBlockTag | DocInlineTagBase): boolean {
+    const hasCorrectKind: boolean = this.syntaxKind === TSDocTagSyntaxKind.InlineTag ?
+      tag instanceof DocInlineTagBase :
+      tag instanceof DocBlockTag;
+    return hasCorrectKind && this.hasTagName(tag.tagNameWithUpperCase);
+  }
+
+  /**
+   * Returns whether the provided tag name is defined by this tag definition.
+   */
+  public hasTagName(tagName: string): boolean {
+    const tagNameWithUpperCase: string = tagName.toUpperCase();
+    return this.tagNameWithUpperCase === tagNameWithUpperCase ||
+      this.synonymsWithUpperCase.indexOf(tagNameWithUpperCase) >= 0;
   }
 }
diff --git a/tsdoc/src/configuration/__tests__/TSDocConfiguration.ts b/tsdoc/src/configuration/__tests__/TSDocConfiguration.ts
new file mode 100644
index 00000000..bb2e8ad3
--- /dev/null
+++ b/tsdoc/src/configuration/__tests__/TSDocConfiguration.ts
@@ -0,0 +1,247 @@
+import { TSDocConfiguration } from '../TSDocConfiguration';
+import { TSDocTagDefinition, TSDocTagSyntaxKind } from '../TSDocTagDefinition';
+
+describe('Synonym overrides', () => {
+    describe('addSynonym', () => {
+        describe('with no existing synonym in base', () => {
+            let configuration: TSDocConfiguration;
+            let baseTag: TSDocTagDefinition;
+            let derivedTag: TSDocTagDefinition;
+            beforeEach(() => {
+                configuration = new TSDocConfiguration();
+                baseTag = new TSDocTagDefinition({
+                    syntaxKind: TSDocTagSyntaxKind.BlockTag,
+                    tagName: '@foo',
+                });
+                configuration.addTagDefinition(baseTag);
+                configuration.setSupportForTag(baseTag, /*supported*/ true);
+                derivedTag = configuration.addSynonym(baseTag, '@bar');
+                afterEach(() => {
+                    configuration = undefined!;
+                    baseTag = undefined!;
+                    derivedTag = undefined!;
+                });
+            });
+            test('does not mutate base tag', () => {
+                expect(baseTag.synonyms).toHaveLength(0);
+            });
+            test('returns a derived tag', () => {
+                expect(derivedTag).not.toBe(baseTag);
+            });
+            test('derived tag has expected synonyms', () => {
+                expect(derivedTag.synonyms).toEqual(['@bar']);
+            });
+            test('derived tag differs from base only in synonyms', () => {
+                expect(derivedTag.tagName).toEqual(baseTag.tagName);
+                expect(derivedTag.tagNameWithUpperCase).toEqual(baseTag.tagNameWithUpperCase);
+                expect(derivedTag.syntaxKind).toEqual(baseTag.syntaxKind);
+                expect(derivedTag.standardization).toEqual(baseTag.standardization);
+                expect(derivedTag.allowMultiple).toEqual(baseTag.allowMultiple);
+                expect(derivedTag.synonyms).not.toEqual(baseTag.synonyms);
+            });
+            test('additional synonym for base returns derived', () => {
+                expect(configuration.addSynonym(baseTag, '@baz')).toBe(derivedTag);
+            });
+            test('additional synonym for derived returns derived', () => {
+                expect(configuration.addSynonym(derivedTag, '@baz')).toBe(derivedTag);
+            });
+            test('additional synonym for derived mutates derived', () => {
+                configuration.addSynonym(derivedTag, '@baz')
+                expect(derivedTag.synonyms).toEqual(['@bar', '@baz']);
+            });
+            test('derived replaces base in tagDefinitions', () => {
+                expect(configuration.tagDefinitions).toHaveLength(1);
+                expect(configuration.tagDefinitions[0]).toBe(derivedTag);
+            });
+            test('derived replaces base in supportedTagDefinitions', () => {
+                expect(configuration.supportedTagDefinitions).toHaveLength(1);
+                expect(configuration.supportedTagDefinitions[0]).toBe(derivedTag);
+            });
+            test('derived tag reachable by name', () => {
+                expect(configuration.tryGetTagDefinition('@foo')).toBe(derivedTag);
+            });
+            test('derived tag reachable by synonym', () => {
+                expect(configuration.tryGetTagDefinition('@bar')).toBe(derivedTag);
+            });
+            test('configured tag of base is derived tag', () => {
+                expect(configuration.getConfiguredTagDefinition(baseTag)).toBe(derivedTag);
+            });
+            test('configured tag of derived is derived tag', () => {
+                expect(configuration.getConfiguredTagDefinition(derivedTag)).toBe(derivedTag);
+            });
+        });
+        describe('for existing synonym in base', () => {
+            let configuration: TSDocConfiguration;
+            let baseTag: TSDocTagDefinition;
+            let baseTagAfterAddExisting: TSDocTagDefinition;
+            beforeEach(() => {
+                configuration = new TSDocConfiguration();
+                baseTag = new TSDocTagDefinition({
+                    syntaxKind: TSDocTagSyntaxKind.BlockTag,
+                    tagName: '@foo',
+                    synonyms: ['@bar']
+                });
+                configuration.addTagDefinition(baseTag);
+                configuration.setSupportForTag(baseTag, /*supported*/ true);
+                baseTagAfterAddExisting = configuration.addSynonym(baseTag, '@bar');
+                afterEach(() => {
+                    configuration = undefined!;
+                    baseTag = undefined!;
+                    baseTagAfterAddExisting = undefined!;
+                });
+            });
+            test('does not modify base tag', () => {
+                expect(baseTag.synonyms).toEqual(['@bar']);
+            });
+            test('returns the base tag', () => {
+                expect(baseTagAfterAddExisting).toBe(baseTag);
+            });
+            test('base tag reachable by name', () => {
+                expect(configuration.tryGetTagDefinition('@foo')).toBe(baseTag);
+            });
+            test('base tag reachable by synonym', () => {
+                expect(configuration.tryGetTagDefinition('@bar')).toBe(baseTag);
+            });
+            test('configured tag of base is base tag', () => {
+                expect(configuration.getConfiguredTagDefinition(baseTag)).toBe(baseTag);
+            });
+            describe('additional synonym', () => {
+                let derivedTag: TSDocTagDefinition;
+                beforeEach(() => {
+                    derivedTag = configuration.addSynonym(baseTag, '@baz');
+                    afterEach(() => {
+                        derivedTag = undefined!;
+                    });
+                });
+                test('does not modify base tag', () => {
+                    expect(baseTag.synonyms).toEqual(['@bar']);
+                });
+                test('returns a derived tag', () => {
+                    expect(derivedTag).not.toBe(baseTag);
+                });
+                test('does not modify base tag', () => {
+                    expect(baseTag.synonyms).toHaveLength(0);
+                });
+                test('derived replaces base in tagDefinitions', () => {
+                    expect(configuration.tagDefinitions).toHaveLength(1);
+                    expect(configuration.tagDefinitions[0]).toBe(derivedTag);
+                });
+                test('derived replaces base in supportedTagDefinitions', () => {
+                    expect(configuration.supportedTagDefinitions).toHaveLength(1);
+                    expect(configuration.supportedTagDefinitions[0]).toBe(derivedTag);
+                });
+                    test('derived tag reachable by name', () => {
+                    expect(configuration.tryGetTagDefinition('@foo')).toBe(derivedTag);
+                });
+                test('derived tag reachable by synonym', () => {
+                    expect(configuration.tryGetTagDefinition('@baz')).toBe(derivedTag);
+                });
+                test('configured tag of base is derived tag', () => {
+                    expect(configuration.getConfiguredTagDefinition(baseTag)).toBe(derivedTag);
+                });
+                test('configured tag of derived is derived tag', () => {
+                    expect(configuration.getConfiguredTagDefinition(derivedTag)).toBe(derivedTag);
+                });
+            });
+        });
+    });
+    describe('removeSynonym', () => {
+        describe('with no existing synonym in base', () => {
+            let configuration: TSDocConfiguration;
+            let baseTag: TSDocTagDefinition;
+            let derivedTag: TSDocTagDefinition;
+            let derivedTagAfterRemove: TSDocTagDefinition;
+            beforeEach(() => {
+                configuration = new TSDocConfiguration();
+                baseTag = new TSDocTagDefinition({
+                    syntaxKind: TSDocTagSyntaxKind.BlockTag,
+                    tagName: '@foo',
+                });
+                configuration.addTagDefinition(baseTag);
+                derivedTag = configuration.addSynonym(baseTag, '@bar');
+                derivedTagAfterRemove = configuration.removeSynonym(baseTag, '@bar');
+                afterEach(() => {
+                    configuration = undefined!;
+                    baseTag = undefined!;
+                    derivedTag = undefined!;
+                    derivedTagAfterRemove = undefined!;
+                });
+            });
+            test('returned tag remains derived', () => {
+                expect(derivedTagAfterRemove).toBe(derivedTag);
+            });
+            test('mutates synonyms on derived', () => {
+                expect(derivedTag.synonyms).toHaveLength(0);
+            });
+            test('derived replaces base in tagDefinitions', () => {
+                expect(configuration.tagDefinitions).toHaveLength(1);
+                expect(configuration.tagDefinitions[0]).toBe(derivedTag);
+            });
+            test('derived replaces base in supportedTagDefinitions', () => {
+                expect(configuration.supportedTagDefinitions).toHaveLength(1);
+                expect(configuration.supportedTagDefinitions[0]).toBe(derivedTag);
+            });
+            test('derived tag reachable by name', () => {
+                expect(configuration.tryGetTagDefinition('@foo')).toBe(derivedTag);
+            });
+            test('nothing reachable by synonym', () => {
+                expect(configuration.tryGetTagDefinition('@bar')).toBeUndefined();
+            });
+            test('configured tag of base is derived tag', () => {
+                expect(configuration.getConfiguredTagDefinition(baseTag)).toBe(derivedTag);
+            });
+            test('configured tag of derived is derived tag', () => {
+                expect(configuration.getConfiguredTagDefinition(derivedTag)).toBe(derivedTag);
+            });
+        });
+        describe('with existing synonym in base', () => {
+            let configuration: TSDocConfiguration;
+            let baseTag: TSDocTagDefinition;
+            let derivedTag: TSDocTagDefinition;
+            beforeEach(() => {
+                configuration = new TSDocConfiguration();
+                baseTag = new TSDocTagDefinition({
+                    syntaxKind: TSDocTagSyntaxKind.BlockTag,
+                    tagName: '@foo',
+                    synonyms: ['@bar']
+                });
+                configuration.addTagDefinition(baseTag);
+                derivedTag = configuration.removeSynonym(baseTag, '@bar');
+                afterEach(() => {
+                    configuration = undefined!;
+                    baseTag = undefined!;
+                    derivedTag = undefined!;
+                });
+            });
+            test('does not mutate base tag', () => {
+                expect(baseTag.synonyms).toEqual(['@bar']);
+            });
+            test('returns a derived tag', () => {
+                expect(derivedTag).not.toBe(baseTag);
+            });
+            test('derived tag has expected synonyms', () => {
+                expect(derivedTag.synonyms).toHaveLength(0);
+            });
+            test('derived replaces base in tagDefinitions', () => {
+                expect(configuration.tagDefinitions).toHaveLength(1);
+                expect(configuration.tagDefinitions[0]).toBe(derivedTag);
+            });
+            test('derived replaces base in supportedTagDefinitions', () => {
+                expect(configuration.supportedTagDefinitions).toHaveLength(1);
+                expect(configuration.supportedTagDefinitions[0]).toBe(derivedTag);
+            });
+            test('derived tag reachable by name', () => {
+                expect(configuration.tryGetTagDefinition('@foo')).toBe(derivedTag);
+            });
+            test('nothing reachable by synonym', () => {
+                expect(configuration.tryGetTagDefinition('@bar')).toBeUndefined();
+            });
+            test('configured tag of base is derived tag', () => {
+                expect(configuration.getConfiguredTagDefinition(baseTag)).toBe(derivedTag);
+            });
+            test('configured tag of derived is derived tag', () => {
+                expect(configuration.getConfiguredTagDefinition(derivedTag)).toBe(derivedTag);
+            });
+        });
+    });
+});
\ No newline at end of file
diff --git a/tsdoc/src/details/ModifierTagSet.ts b/tsdoc/src/details/ModifierTagSet.ts
index 2e976546..607b74a2 100644
--- a/tsdoc/src/details/ModifierTagSet.ts
+++ b/tsdoc/src/details/ModifierTagSet.ts
@@ -1,5 +1,13 @@
 import { DocBlockTag } from '../nodes/DocBlockTag';
 import { TSDocTagDefinition, TSDocTagSyntaxKind } from '../configuration/TSDocTagDefinition';
+import { TSDocConfiguration } from '../configuration/TSDocConfiguration';
+
+/**
+ * Constructor parameters for {@link ModifierTagSet}.
+ */
+export interface IModifierTagSetParameters {
+  configuration: TSDocConfiguration;
+}
 
 /**
  * Represents a set of modifier tags that were extracted from a doc comment.
@@ -11,6 +19,8 @@ import { TSDocTagDefinition, TSDocTagSyntaxKind } from '../configuration/TSDocTa
  * signature is internal (i.e. not part of the public API contract).
  */
 export class ModifierTagSet {
+  public readonly configuration: TSDocConfiguration;
+
   private readonly _nodes: DocBlockTag[] = [];
 
   // NOTE: To implement case insensitivity, the keys in this set are always upper-case.
@@ -18,6 +28,14 @@ export class ModifierTagSet {
   // the Turkish "i" character correctly).
   private readonly _nodesByName: Map<string, DocBlockTag> = new Map<string, DocBlockTag>();
 
+  /**
+   * Don't call this directly.  Instead use {@link TSDocParser}
+   * @internal
+   */
+  public constructor(parameters: IModifierTagSetParameters) {
+    this.configuration = parameters.configuration;
+  }
+
   /**
    * The original block tag nodes that defined the modifiers in this set, excluding duplicates.
    */
@@ -36,8 +54,7 @@ export class ModifierTagSet {
 
   /**
    * Returns true if the set contains a DocBlockTag matching the specified tag definition.
-   * Note that synonyms are not considered.  The comparison is case-insensitive.
-   * The TSDocTagDefinition must be a modifier tag.
+   * The comparison is case-insensitive.  The TSDocTagDefinition must be a modifier tag.
    * @param tagName - The name of the tag, including the `@` prefix  For example, `@internal`
    */
   public hasTag(modifierTagDefinition: TSDocTagDefinition): boolean {
@@ -53,7 +70,19 @@ export class ModifierTagSet {
     if (modifierTagDefinition.syntaxKind !== TSDocTagSyntaxKind.ModifierTag) {
       throw new Error('The tag definition is not a modifier tag');
     }
-    return this._nodesByName.get(modifierTagDefinition.tagNameWithUpperCase);
+
+    const configuredTagDefinition: TSDocTagDefinition
+      = this.configuration.getConfiguredTagDefinition(modifierTagDefinition);
+
+    let tag: DocBlockTag | undefined =
+      this._nodesByName.get(configuredTagDefinition.tagNameWithUpperCase);
+    if (!tag) {
+      for (const synonym of configuredTagDefinition.synonymsWithUpperCase) {
+        tag = this._nodesByName.get(synonym);
+        if (tag) break;
+      }
+    }
+    return tag;
   }
 
   /**
diff --git a/tsdoc/src/details/StandardTags.ts b/tsdoc/src/details/StandardTags.ts
index 72ee1ac5..af7b51a6 100644
--- a/tsdoc/src/details/StandardTags.ts
+++ b/tsdoc/src/details/StandardTags.ts
@@ -68,6 +68,7 @@ export class StandardTags {
    */
   public static readonly defaultValue: TSDocTagDefinition = StandardTags._defineTag({
     tagName: '@defaultValue',
+    synonyms: ['@default'],
     syntaxKind: TSDocTagSyntaxKind.BlockTag,
     standardization: Standardization.Extended
   });
@@ -234,6 +235,7 @@ export class StandardTags {
    */
   public static readonly param: TSDocTagDefinition = StandardTags._defineTag({
     tagName: '@param',
+    synonyms: ['@arg', '@argument'],
     syntaxKind: TSDocTagSyntaxKind.BlockTag,
     allowMultiple: true,
     standardization: Standardization.Core
@@ -307,6 +309,7 @@ export class StandardTags {
    */
   public static readonly returns: TSDocTagDefinition = StandardTags._defineTag({
     tagName: '@returns',
+    synonyms: ['@return'],
     syntaxKind: TSDocTagSyntaxKind.BlockTag,
     standardization: Standardization.Core
   });
@@ -328,6 +331,31 @@ export class StandardTags {
     standardization: Standardization.Extended
   });
 
+  /**
+   * (Extended)
+   *
+   * Used to document another symbol or resource that may be related to the current item being documented.
+   *
+   * @remarks
+   *
+   * For example:
+   *
+   * ```ts
+   * /**
+   *  * Make a rectangle from two points.
+   *  *
+   *  * @see {@link Point}
+   *  &#42;/
+   * function makeRect(a: Point, b: Point): Rect;
+   * ```
+   */
+  public static readonly see: TSDocTagDefinition = StandardTags._defineTag({
+    tagName: '@see',
+    synonyms: ['@seeAlso'],
+    syntaxKind: TSDocTagSyntaxKind.BlockTag,
+    standardization: Standardization.Extended
+  });
+
   /**
    * (Extended)
    *
@@ -361,6 +389,7 @@ export class StandardTags {
    */
   public static readonly throws: TSDocTagDefinition = StandardTags._defineTag({
     tagName: '@throws',
+    synonyms: ['@exception'],
     syntaxKind: TSDocTagSyntaxKind.BlockTag,
     allowMultiple: true,
     standardization: Standardization.Extended
@@ -375,6 +404,7 @@ export class StandardTags {
    */
   public static readonly typeParam: TSDocTagDefinition = StandardTags._defineTag({
     tagName: '@typeParam',
+    synonyms: ['@template'],
     syntaxKind: TSDocTagSyntaxKind.BlockTag,
     allowMultiple: true,
     standardization: Standardization.Core
@@ -420,6 +450,7 @@ export class StandardTags {
     StandardTags.remarks,
     StandardTags.returns,
     StandardTags.sealed,
+    StandardTags.see,
     StandardTags.throws,
     StandardTags.typeParam,
     StandardTags.virtual
diff --git a/tsdoc/src/emitters/TSDocEmitter.ts b/tsdoc/src/emitters/TSDocEmitter.ts
index 44d6d125..47d3f6db 100644
--- a/tsdoc/src/emitters/TSDocEmitter.ts
+++ b/tsdoc/src/emitters/TSDocEmitter.ts
@@ -96,7 +96,7 @@ export class TSDocEmitter {
         this._ensureLineSkipped();
         this._renderNode(docBlock.blockTag);
 
-        if (docBlock.blockTag.tagNameWithUpperCase === StandardTags.returns.tagNameWithUpperCase) {
+        if (StandardTags.returns.isDefinitionOfTag(docBlock.blockTag)) {
           this._writeContent(' ');
           this._hangingParagraph = true;
         }
@@ -130,6 +130,7 @@ export class TSDocEmitter {
           docComment.typeParams,
           docComment.returnsBlock,
           ...docComment.customBlocks,
+          ...docComment.seeBlocks,
           docComment.inheritDocTag
         ]);
         if (docComment.modifierTagSet.nodes.length > 0) {
diff --git a/tsdoc/src/nodes/DocComment.ts b/tsdoc/src/nodes/DocComment.ts
index 36428446..4a3945c3 100644
--- a/tsdoc/src/nodes/DocComment.ts
+++ b/tsdoc/src/nodes/DocComment.ts
@@ -1,6 +1,8 @@
 import { DocNode, DocNodeKind, IDocNodeParameters } from './DocNode';
 import { DocSection } from './DocSection';
 import { StandardModifierTagSet } from '../details/StandardModifierTagSet';
+import { IModifierTagSetParameters } from '../details/ModifierTagSet';
+import { StandardTags } from '../details/StandardTags';
 import { DocBlock } from './DocBlock';
 import { DocInheritDocTag } from './DocInheritDocTag';
 import { StringBuilder } from '../emitters/StringBuilder';
@@ -87,6 +89,7 @@ export class DocComment extends DocNode {
    */
   public readonly modifierTagSet: StandardModifierTagSet;
 
+  private _seeBlocks: DocBlock[];
   private _customBlocks: DocBlock[];
 
   /**
@@ -103,9 +106,9 @@ export class DocComment extends DocNode {
     this.params = new DocParamCollection({ configuration: this.configuration });
     this.typeParams = new DocParamCollection({ configuration: this.configuration });
     this.returnsBlock = undefined;
+    this.modifierTagSet = new StandardModifierTagSet({ configuration: this.configuration });
 
-    this.modifierTagSet = new StandardModifierTagSet();
-
+    this._seeBlocks = [];
     this._customBlocks = [];
   }
 
@@ -114,6 +117,13 @@ export class DocComment extends DocNode {
     return DocNodeKind.Comment;
   }
 
+  /**
+   * The collection of all `@see` DocBlockTag nodes belonging to this doc comment.
+   */
+  public get seeBlocks(): ReadonlyArray<DocBlock> {
+    return this._seeBlocks;
+  }
+
   /**
    * The collection of all DocBlock nodes belonging to this doc comment.
    */
@@ -121,6 +131,16 @@ export class DocComment extends DocNode {
     return this._customBlocks;
   }
 
+  /**
+   * Append an item to the seeBlocks collection.
+   */
+  public appendSeeBlock(block: DocBlock): void {
+    if (!StandardTags.see.isDefinitionOfTag(block.blockTag)) {
+      throw new Error("Provided block is not a @see block.");
+    }
+    this._seeBlocks.push(block);
+  }
+
   /**
    * Append an item to the customBlocks collection.
    */
@@ -139,6 +159,7 @@ export class DocComment extends DocNode {
       this.typeParams.count > 0 ? this.typeParams : undefined,
       this.returnsBlock,
       ...this.customBlocks,
+      ...this.seeBlocks,
       this.inheritDocTag,
       ...this.modifierTagSet.nodes
     ];
@@ -167,3 +188,4 @@ export class DocComment extends DocNode {
 
 // Circular reference
 import { TSDocEmitter } from '../emitters/TSDocEmitter';
+
diff --git a/tsdoc/src/nodes/DocLinkTag.ts b/tsdoc/src/nodes/DocLinkTag.ts
index 134a0570..dbd8bc44 100644
--- a/tsdoc/src/nodes/DocLinkTag.ts
+++ b/tsdoc/src/nodes/DocLinkTag.ts
@@ -7,6 +7,7 @@ import {
 } from './DocInlineTagBase';
 import { DocExcerpt, ExcerptKind } from './DocExcerpt';
 import { TokenSequence } from '../parser/TokenSequence';
+import { StandardTags } from '../details/StandardTags';
 
 /**
  * Constructor parameters for {@link DocLinkTag}.
@@ -62,7 +63,7 @@ export class DocLinkTag extends DocInlineTagBase {
   public constructor(parameters: IDocLinkTagParameters | IDocLinkTagParsedParameters) {
     super(parameters);
 
-    if (this.tagNameWithUpperCase !== '@LINK') {
+    if (!StandardTags.link.hasTagName(this.tagNameWithUpperCase)) {
       throw new Error('DocLinkTag requires the tag name to be "{@link}"');
     }
 
diff --git a/tsdoc/src/parser/NodeParser.ts b/tsdoc/src/parser/NodeParser.ts
index 764611c1..3f10127b 100644
--- a/tsdoc/src/parser/NodeParser.ts
+++ b/tsdoc/src/parser/NodeParser.ts
@@ -276,14 +276,14 @@ export class NodeParser {
     if (tagDefinition) {
       switch (tagDefinition.syntaxKind) {
         case TSDocTagSyntaxKind.BlockTag:
-          if (docBlockTag.tagNameWithUpperCase === StandardTags.param.tagNameWithUpperCase) {
+          if (StandardTags.param.isDefinitionOfTag(docBlockTag)) {
             const docParamBlock: DocParamBlock = this._parseParamBlock(tokenReader, docBlockTag, StandardTags.param.tagName);
 
             this._parserContext.docComment.params.add(docParamBlock);
 
             this._currentSection = docParamBlock.content;
             return;
-          } else if (docBlockTag.tagNameWithUpperCase === StandardTags.typeParam.tagNameWithUpperCase) {
+          } else if (StandardTags.typeParam.isDefinitionOfTag(docBlockTag)) {
             const docParamBlock: DocParamBlock = this._parseParamBlock(tokenReader, docBlockTag, StandardTags.typeParam.tagName);
 
             this._parserContext.docComment.typeParams.add(docParamBlock);
@@ -315,22 +315,18 @@ export class NodeParser {
 
   private _addBlockToDocComment(block: DocBlock): void {
     const docComment: DocComment = this._parserContext.docComment;
-
-    switch (block.blockTag.tagNameWithUpperCase) {
-      case StandardTags.remarks.tagNameWithUpperCase:
-        docComment.remarksBlock = block;
-        break;
-      case StandardTags.privateRemarks.tagNameWithUpperCase:
-        docComment.privateRemarks = block;
-        break;
-      case StandardTags.deprecated.tagNameWithUpperCase:
-        docComment.deprecatedBlock = block;
-        break;
-      case StandardTags.returns.tagNameWithUpperCase:
-        docComment.returnsBlock = block;
-        break;
-      default:
-        docComment.appendCustomBlock(block);
+    if (StandardTags.remarks.isDefinitionOfTag(block.blockTag)) {
+      docComment.remarksBlock = block;
+    } else if (StandardTags.privateRemarks.isDefinitionOfTag(block.blockTag)) {
+      docComment.privateRemarks = block;
+    } else if (StandardTags.deprecated.isDefinitionOfTag(block.blockTag)) {
+      docComment.deprecatedBlock = block;
+    } else if (StandardTags.returns.isDefinitionOfTag(block.blockTag)) {
+      docComment.returnsBlock = block;
+    } else if (StandardTags.see.isDefinitionOfTag(block.blockTag)) {
+      docComment.appendSeeBlock(block);
+    } else {
+      docComment.appendCustomBlock(block);
     }
   }
 
@@ -816,15 +812,12 @@ export class NodeParser {
       tagContentExcerpt ? tagContentExcerpt : TokenSequence.createEmpty(this._parserContext));
 
     let docNode: DocNode;
-    switch (tagNameWithUpperCase) {
-      case StandardTags.inheritDoc.tagNameWithUpperCase:
-        docNode = this._parseInheritDocTag(docInlineTagParsedParameters, embeddedTokenReader);
-        break;
-      case StandardTags.link.tagNameWithUpperCase:
-        docNode = this._parseLinkTag(docInlineTagParsedParameters, embeddedTokenReader);
-        break;
-      default:
-        docNode = new DocInlineTag(docInlineTagParsedParameters);
+    if (StandardTags.inheritDoc.hasTagName(tagNameWithUpperCase)) {
+      docNode = this._parseInheritDocTag(docInlineTagParsedParameters, embeddedTokenReader);
+    } else if (StandardTags.link.hasTagName(tagNameWithUpperCase)) {
+      docNode = this._parseLinkTag(docInlineTagParsedParameters, embeddedTokenReader);
+    } else {
+      docNode = new DocInlineTag(docInlineTagParsedParameters);
     }
 
     // Validate the tag