← Methods repository
CONCEPTFOUNDATIONALPYTHON · R4 citations

SNOMED CT Clinical Terminology

A comprehensive, polyhierarchical clinical terminology — not a billing classification — that assigns numeric concept identifiers to clinical findings, disorders, procedures, and observable entities, enabling granular EHR phenotyping via descendant-hierarchy expansion and serving as the standard Condition vocabulary in the OMOP Common Data Model.

Data Standardcoding-systemdata-standardprimitiveterminologyehrsnomedsnomed-ctomop
On this page
Methods reference only. Use primary source citations and local policy before applying this in a study protocol, regulatory submission, payer dossier, or clinical decision.
In plain language

SNOMED CT is the world's largest clinical terminology — a giant dictionary that gives each clinical concept (a disease, a finding, a procedure) its own permanent numeric ID and connects those concepts in a hierarchy, so that searching for 'diabetes mellitus' automatically includes all the specific subtypes below it. Unlike ICD codes, which are designed for insurance billing and lump many things together, SNOMED CT is designed for clinical documentation and can describe what a clinician actually saw or decided with high precision. It is most commonly encountered in electronic health record (EHR) problem lists and is the vocabulary that the OMOP data model uses to store diagnoses — so understanding SNOMED CT is a prerequisite for understanding OMOP concept sets.

When to use it
Prefer SNOMED CT when working from EHR source data, OMOP CDM, or registry data where clinical granularity is required; prefer ICD-10-CM when working from raw US administrative claims.
Use native SNOMED CT when the data source is not OMOP-formatted, when auditing OMOP mapping quality, or when working in a terminology-native environment (EHR CDS, ontology tooling).
Use SNOMED CT descendant expansion as the first-pass candidate set for phenotyping; layer additional logic (confirmation windows, code-position requirements, lab confirmation) on top via a validated algorithm when the...
Watch out for
SNOMED CT does not appear in US insurance claims — administrative data uses ICD-10-CM for billing. Working with SNOMED CT requires an explicit mapping step when combining EHR and claims data.
Native RF2 querying requires building a transitive closure of the |is a| relationship table, which is more complex than OMOP's pre-computed CONCEPT_ANCESTOR table.
Hierarchy-based expansion alone has no mechanism for requiring confirmation (1 inpatient or 2 outpatient codes), excluding rule-out coding, or incorporating non-structured data (labs, vitals, notes).

SNOMED CT

(Systematized Nomenclature of Medicine — Clinical Terms) is the world's most comprehensive clinical terminology and the vocabulary of record for capturing clinical meaning at the point of care. It is maintained by SNOMED International (a not-for-profit association of national member bodies) and distributed in the United States by the National Library of Medicine (NLM) through the US Edition.

Use requires a license; in member countries, including the United States, that license is free — US users obtain access through the NLM's UMLS Metathesaurus license, which covers SNOMED CT for US purposes. Small illustrative examples with attribution to SNOMED International are acceptable; bulk reproduction of SNOMED CT content is not.

Core conceptual distinction: terminology vs classification

The single most important thing to understand about SNOMED CT is what it is not: it is not a billing classification. ICD-10-CM (and its predecessors) was designed for statistical, administrative, and reimbursement purposes — its categories are mutually exclusive, its hierarchy is coarse, and a single code often collapses many clinically distinct entities for the practical convenience of counting and billing.

SNOMED CT was designed for the opposite purpose: to capture the full clinical meaning of what a clinician observed, recorded, or decided, with enough granularity and structure to support clinical decision support, research phenotyping, and inter-system exchange. This distinction is the conceptual spine of every RWE use case: ICD-10-CM tells you what was billed; SNOMED CT tells you (or tries to tell you) what actually happened clinically.

Three core components

Every concept in SNOMED CT has three mandatory elements. First, a concept — a unique, atomic clinical idea identified by a numeric concept identifier (SCTID) that is 6–18 digits long and encodes a partition (the type of component) and a Verhoeff check digit. The concept identifier is opaque and permanent: 44054006 represents |Diabetes mellitus type 2| in every edition, every country, every year it has existed.

Second, descriptions — one or more human-readable labels for the concept, split into a single Fully Specified Name (FSN, which is globally unique and unambiguous), one Preferred Term (the display label for a locale), and zero or more Synonyms and Acceptable Terms. A single concept may have many acceptable terms; 73211009 has both |Diabetes mellitus| and |DM| as accepted synonyms. Third, relationships — formal machine-readable links between concepts, stored in the RF2 Relationship table. The most important relationship type is |Is a| (SCTID 116680003), which builds the hierarchy.

The |is a| polyhierarchy

Unlike ICD-10-CM's tree — where each code has exactly one parent — SNOMED CT is a directed acyclic graph (DAG). A concept can have multiple parents, making it polyhierarchical. For example, 44054006 |Diabetes mellitus type 2| is a child of both 73211009 |Diabetes mellitus| (the metabolic disorder lineage) and of 8801005 |Secondary diabetes mellitus| if the concept is inherited from multiple classification facets.

This means descendant queries must traverse a graph, not a tree, typically via a transitive closure of |is a| relationships over the RF2 Relationship file — every concept that can reach a root concept through a chain of |is a| edges is a descendant.

The practical upshot for RWE is that a concept-set built by "all descendants of 73211009 |Diabetes mellitus|" will capture far more granular codes than any flat ICD list, but the membership of that concept-set changes between SNOMED CT releases (twice yearly for the US Edition) as new concepts are added and retired.

Defining attribute relationships

Beyond |is a|, SNOMED CT uses additional relationship types — called defining attributes — to formally specify what makes a concept what it is. Clinical findings carry attributes such as |finding site| (which body structure is affected) and |associated morphology| (what is structurally abnormal). Disorders carry |causative agent|, |pathological process|, and others. These attributes power description logic classifiers (such as EL++ reasoners) that can infer implied subsumption relationships and detect modeling errors.

For most RWE users, attribute relationships are background machinery; for advanced use cases (clinical decision support, automated phenotype generation), they are how SNOMED CT earns its designation as a "formal ontology" rather than a flat vocabulary.

Pre-coordination vs post-coordination

SNOMED CT concepts are either pre-coordinated — where a single SCTID expresses a complete clinical idea (e.g., 44054006 |Diabetes mellitus type 2|) — or post-coordinated, where a base concept is combined with additional expressions using SNOMED's Compositional Grammar to capture a nuanced clinical statement not represented by any single concept (e.g., a finding site applied to a generic finding concept at the point of documentation).

Post-coordination is theoretically powerful but is rarely supported at the EHR interface level; most RWE work operates exclusively on pre-coordinated concepts from problem lists and encounter diagnoses.

Pros, cons, and trade-offs — specific and comparative

  • vs ICD-10-CM (the dominant alternative for condition coding in US claims): SNOMED CT's polyhierarchy enables descendant expansion, meaning a single query "find all concepts below 73211009 |Diabetes mellitus|" returns hundreds of granular concepts — type 1, type 2, maturity onset, gestational, drug-induced, and rare monogenic subtypes — without requiring the analyst to enumerate them individually. ICD-10-CM requires manual code list curation; adding a new ICD code requires updating every code list that should include it. SNOMED CT also preserves synonymy (many terms → one concept), so free-text and structured entry with different labels resolve to the same computable unit. Cons: SNOMED CT is not in US administrative claims — clinical encounter data must be coded in ICD-10-CM for billing — so SNOMED exists in the EHR, not in the payer file. The two vocabularies require an explicit crosswalk. Prefer SNOMED CT when working from EHR or registry source data with rich clinical terminology; prefer ICD-10-CM when your primary source is US insurance claims.
  • vs flat proprietary code lists (e.g., hand-curated ICD code lists for a specific indication): A SNOMED CT-based concept set updates automatically as new descendant concepts are added to the terminology, whereas a flat list requires manual maintenance. Cons: SNOMED CT concept membership changes between releases, making reproducibility dependent on pinning the terminology version; a concept set built against the 2023-09 US Edition may have slightly different membership than one built against the 2024-03 US Edition. Prefer SNOMED CT descendant sets for maintainability in longitudinal or multi-database studies; use version-pinning and document the release date in your methods.
  • vs OMOP Concept Sets (which use SNOMED under the hood): OMOP's CONDITION_OCCURRENCE table stores diagnoses using SNOMED CT as its standard vocabulary — source ICD-9/10-CM codes are mapped to SNOMED standard concepts via the OMOP vocabulary "Maps to" relationship. The OMOP Atlas tool's concept-set builder applies descendant expansion using the same |is a| hierarchy, so OMOP concept sets are SNOMED CT descendant queries packaged in a user interface. Understanding SNOMED CT structure is therefore a prerequisite for understanding OMOP concept-set logic. Cons: The OMOP mapping layer (ICD→SNOMED) introduces mapping errors and losses; a source ICD code may map to a SNOMED concept that is too broad or too narrow, and some source codes are explicitly excluded from mapping ("Maps to" nothing). Audit the mapping before relying on OMOP concept-set coverage.
  • vs LOINC (laboratory/observation coding) and RxNorm (drug coding): SNOMED CT, LOINC, and RxNorm are complementary, not competing. SNOMED CT covers clinical findings, disorders, procedures, body structures, and organisms; LOINC covers the identity of a laboratory test or observation; RxNorm covers drugs and their ingredients. All three are required for a complete clinical representation. OMOP uses all three in their respective domains (Condition→SNOMED; Measurement→LOINC; Drug→RxNorm). Prefer the domain-appropriate vocabulary in each context; do not substitute SNOMED for LOINC in lab-based phenotyping or for RxNorm in drug exposure definitions.

When NOT to use — and when it is actively misleading or dangerous

  • Do not use SNOMED CT as a drop-in replacement for ICD-10-CM in US claims analysis. US insurance claims are coded in ICD-10-CM for billing; SNOMED does not appear in the adjudicated claim record. Applying a SNOMED-based code list to a raw claims table without an explicit mapping step will return no rows and produce silently empty cohorts — a failure mode that is not always immediately obvious.
  • Do not ignore the terminology version. SNOMED CT releases in the United States occur twice yearly (January and July). Concept content, descriptions, and relationship definitions change between releases. A cohort built without specifying the SNOMED CT release date is not reproducible. Always pin the terminology version in your methods and SAP.
  • Do not conflate problem-list SNOMED entries with encounter diagnoses. In EHR systems that use SNOMED CT for problem list documentation, a concept entered on the problem list may persist for years without update, representing the patient's chronic conditions at time of entry — not a fresh clinical judgment. Encounter diagnoses, by contrast, are event-based. Mixing these provenance types in a descendant-expansion query can inflate prevalence estimates and misattribute timing.
  • Do not assume the SNOMED→ICD-10-CM map is lossless. SNOMED International publishes a rule-based map from SNOMED CT concepts to ICD-10 for reimbursement derivation. This map is lossy in both directions: multiple SNOMED concepts map to the same ICD code (granularity is lost in the ICD→SNOMED direction), and some SNOMED concepts have no ICD equivalent or map to "unspecified" codes. Using a derived ICD code from a SNOMED source concept in a claims validation context can introduce systematic misclassification.
  • Do not use SNOMED CT for medication coding. SNOMED CT includes a Substance hierarchy and some Clinical Drug concepts, but RxNorm is the designated vocabulary for drug exposure in OMOP and in most US EHR interoperability standards. Using SNOMED for drug coding duplicates capability that is better served by RxNorm and introduces a non-standard pattern that most ETL pipelines will not support.

Data-source operational depth

  • EHR: SNOMED CT is most commonly present in EHR data as the vocabulary behind problem lists (the clinician's running list of the patient's active conditions) and, in some implementations, encounter diagnoses. Problem-list capture is clinician-driven: conditions are added at clinical discretion and may be carried forward indefinitely without update, meaning a resolved condition may still appear as "active" in a SNOMED problem-list query years after resolution. Encounter diagnoses are event-level and more analogous to claims diagnoses but may be coded at various levels of specificity depending on the EHR's interface and the clinician's coding habits. In OMOP ETLs from EHR source data, the `condition_type_concept_id` distinguishes problem-list entries from encounter diagnoses, and this provenance metadata is critical for RWE studies where the timing and recurrence of the condition are analytically relevant.
  • Registry: Disease registries frequently use SNOMED CT for condition coding, often with tighter clinical curation (oncology registries, rare-disease registries). Registry SNOMED data tends to be highly precise for the index condition but may be absent for comorbidities and is rarely present for drug exposure, which still requires claims or pharmacy linkage.
  • Linked EHR-claims: The ideal configuration for SNOMED-based RWE — EHR provides SNOMED-coded clinical granularity (problem-list subtype, lab values, vitals, pathology) while claims provide complete drug exposure and a defined enrollment denominator. The linkage must reconcile SNOMED problem-list dates with ICD claim dates; these will often differ because the problem-list date reflects when the condition was first documented in this EHR, not when the patient first had the condition or when the claim was generated.
  • OMOP CDM: In OMOP, the CONDITION_OCCURRENCE table stores SNOMED CT concept IDs as the standard vocabulary for conditions. The ETL maps source ICD-9-CM or ICD-10-CM codes to SNOMED using the "Maps to" relationship in the OMOP vocabulary tables. Descendant queries are executed using the CONCEPT_ANCESTOR table, which pre-computes the transitive closure of the |is a| hierarchy — exactly the operation you would perform manually over the RF2 Relationship file. Always verify the ETL mapping completeness: not all source codes map to SNOMED concepts (some are excluded), and mapping quality varies across CDM vintages and ETL implementations.

Licensing note

SNOMED CT is owned by SNOMED International. Use requires a license. In member countries — which include the United States — access is free for most users. US users should obtain access through the NLM via a UMLS license (https://www.nlm.nih.gov/healthit/snomedct/index.html). Do not bulk-reproduce SNOMED CT content; small illustrative examples with attribution to SNOMED International are acceptable.

Decision diagram

flowchart TD
  ROOT["73211009<br/>|Diabetes mellitus|<br/>(root concept)"]
  ROOT --> T2["44054006<br/>|Diabetes mellitus type 2|"]
  ROOT --> T1["46635009<br/>|Diabetes mellitus type 1|"]
  ROOT --> GDM["11687002<br/>|Gestational diabetes|"]
  T2 --> MOD["609568004<br/>|Maturity onset diabetes of the young|"]
  T2 --> INS["44054006-INS<br/>|T2DM with insulin|<br/>(illustrative subtype)"]
  T2 --> COMP["73211009-COMP<br/>|T2DM with complication|<br/>(illustrative subtype)"]
  style ROOT fill:#4a90d9,color:#fff
  style T2 fill:#7bb3e8,color:#000
  style T1 fill:#a8d0f0,color:#000
  style GDM fill:#a8d0f0,color:#000
  style MOD fill:#d0e8f8,color:#000
  style INS fill:#d0e8f8,color:#000
  style COMP fill:#d0e8f8,color:#000
Partial |is a| polyhierarchy beneath 73211009 |Diabetes mellitus|. Each concept has a permanent numeric SCTID. A descendant expansion query from 73211009 captures all nodes shown; rooting at 44054006 captures only that subtree. Concept IDs and structure are illustrative — consult the current US Edition for the authoritative hierarchy.

Worked example

Scenario

A pharmacoepidemiologist wants to build a type 2 diabetes cohort from an EHR dataset that has been converted to the OMOP CDM. She needs to understand why a SNOMED CT-based descendant expansion finds more patients than a flat ICD-10-CM code list, and whether the extra patients represent true type 2 diabetes or noise from the broader hierarchy. The example walks through the two approaches on a hypothetical patient database of 100,000 adults, shows the code counts each strategy produces, and computes the incremental capture rate.

Dataset

Comparison of two phenotyping strategies for type 2 diabetes: flat ICD-10-CM list vs SNOMED CT descendant expansion. Row counts are from a hypothetical 100,000-patient EHR-OMOP dataset.

StrategyRoot or seed conceptNumber of codes / concepts in setPatients identifiedNotes
Flat ICD-10-CM listE11 (Type 2 diabetes mellitus) and E11.* subcodes378200Manual enumeration of E11 and its subcategories; must be updated when new ICD codes are added
SNOMED CT descendant expansion44054006 (Diabetes mellitus type 2) and all is-a descendants1128960Automated hierarchy traversal in CONCEPT_ANCESTOR; includes granular clinical subtypes not represented in ICD-10-CM
Incremental patients (SNOMED only)Concepts without ICD-10-CM equivalent or mapping gap75760Patients coded with SNOMED-specific subtypes (e.g., maturity onset diabetes of the young in problem list) that did not have a corresponding E11 claim in the observation window

Steps

1The ICD-10-CM strategy starts with E11 and lists all 37 codes in the E11 family (E11.0 through E11.9 and their 4th/5th digit extensions). Each is looked up in the OMOP CONCEPT table as a source code and then followed via the Maps-to relationship to its SNOMED standard concept. Patients with any CONDITION_OCCURRENCE record carrying one of those SNOMED standard concepts are flagged as cases.
2The SNOMED descendant strategy starts directly with SNOMED concept 44054006 (Diabetes mellitus type 2) and queries the OMOP CONCEPT_ANCESTOR table for all concept_id values where ancestor_concept_id = 201826 (the OMOP standard concept ID for this SNOMED concept) and min_levels_of_separation >= 0, returning 112 descendant concepts across all levels of the hierarchy.
3The SNOMED strategy identifies 8960 patients vs 8200 from the flat ICD list, a difference of 760 patients. That is 760 / 8200 = 0.0927, meaning about 9.3% more patients are captured by descendant expansion.
4On inspection, the 760 extra patients were coded using SNOMED-specific granular subtypes on their EHR problem lists (e.g., maturity onset diabetes of the young type 3, gestational diabetes that evolved to type 2) that either had no direct ICD-10-CM equivalent or whose ICD codes were not present in the claims-derived CONDITION_OCCURRENCE records within the study window.
5Key validation check -- of the 760 incremental patients, chart review of a 50-patient random sample confirms 82% are genuine type 2 diabetes cases documented by clinicians using SNOMED problem-list entries. The 18% are coding errors (wrong hierarchy branch chosen by the EHR interface). PPV of 0.82 for the incremental patients informs whether to include them with a sensitivity analysis or require a corroborating encounter diagnosis.

Result

SNOMED CT descendant expansion identifies 8960 patients vs 8200 from a flat ICD-10-CM code list, capturing 760 / 8200 = 0.0927 more patients (9.3% incremental capture). The 112-concept SNOMED set covers granular clinical subtypes absent from the 37-code ICD list. Version-pinning the SNOMED release and documenting provenance (problem-list vs encounter diagnosis) are required for reproducibility.

Trade-offs

Pros of this
SNOMED CT provides a polyhierarchical concept model that supports descendant expansion (one query captures all subtypes), synonymy resolution (many terms → one concept), and clinical granularity for distinguishing phenotypic subtypes that ICD-10-CM collapses under a single code. SNOMED CT is designed for clinical documentation rather than billing, so it better reflects what the clinician observed.
Pros of this
Understanding SNOMED CT structure directly — rather than through OMOP's ATLAS abstraction — gives the analyst insight into why a concept set has a particular membership, allows debugging of mapping gaps, and enables working with non-OMOP SNOMED data sources (EHR problem lists, registries that deliver native RF2).
Pros of this
Descendant expansion via SNOMED CT hierarchy is a lightweight, transparent single-query phenotyping approach that requires no training data and can be applied to any SNOMED-coded concept. For well-represented conditions in SNOMED, it provides excellent recall.

Runnable example

Two operations: (1) build a transitive closure of the |is a| relationship over the RF2 Relationship file to find all descendants of a given SNOMED CT concept (here: 44054006 Diabetes mellitus type 2); (2) run the equivalent query over an OMOP CONCEPT_ANCESTOR table using SQLite.

requires: pandas · sqlite3
import pandas as pd
import sqlite3

# ── Part 1: RF2-based transitive closure (native SNOMED CT) ──────────────────
# Download the US Edition RF2 from NLM (UMLS licence required).
# The Relationship snapshot file is typically named:
#   sct2_Relationship_Snapshot_US1000124_<YYYYMMDD>.txt

def load_isa_edges(rf2_relationship_file: str) -> dict[str, set[str]]:
    """Return a dict: child_sctid -> set of immediate parent SCTIDs (Is a only)."""
    IS_A = "116680003"  # SCTID for the |Is a| relationship type
    df = pd.read_csv(rf2_relationship_file, sep="\t", dtype=str, usecols=[
        "active", "sourceId", "destinationId", "typeId"
    ])
    df = df[(df["active"] == "1") & (df["typeId"] == IS_A)]
    parents: dict[str, set[str]] = {}
    for _, row in df.iterrows():
        parents.setdefault(row["sourceId"], set()).add(row["destinationId"])
    return parents

def descendants(root_sctid: str, parents: dict[str, set[str]]) -> set[str]:
    """Return all concepts that are a descendant of root_sctid (transitive Is a).
    Uses BFS over the child→parent graph traversed in reverse (child→parent → parent is ancestor).
    """
    # Build child map (parent → set of children) from the parent map
    children: dict[str, set[str]] = {}
    for child, pset in parents.items():
        for p in pset:
            children.setdefault(p, set()).add(child)

    visited: set[str] = set()
    queue = [root_sctid]
    while queue:
        node = queue.pop()
        for child in children.get(node, set()):
            if child not in visited:
                visited.add(child)
                queue.append(child)
    return visited  # does NOT include root_sctid itself

# Example usage (comment out if no RF2 files are available):
# parents = load_isa_edges("sct2_Relationship_Snapshot_US1000124_20240301.txt")
# dm_t2_descendants = descendants("44054006", parents)
# print(f"Found {len(dm_t2_descendants)} descendants of 44054006 |Diabetes mellitus type 2|")

# ── Part 2: OMOP CONCEPT_ANCESTOR query (SQLite example) ─────────────────────
# In a real OMOP environment, replace sqlite3 with your database driver.
# CONCEPT_ANCESTOR stores the pre-computed transitive closure of the Is a hierarchy.

DM_T2_OMOP_CONCEPT_ID = 201826  # OMOP standard concept_id for Diabetes mellitus type 2 (SNOMED 44054006)

def get_omop_descendants(con: sqlite3.Connection, ancestor_concept_id: int) -> pd.DataFrame:
    """Return all OMOP standard concept_ids that are descendants of a given concept.
    min_levels_of_separation = 0 includes the root; >= 1 for descendants only.
    """
    query = """
    SELECT
        ca.descendant_concept_id,
        c.concept_name,
        c.vocabulary_id,
        ca.min_levels_of_separation
    FROM concept_ancestor ca
    JOIN concept c ON c.concept_id = ca.descendant_concept_id
    WHERE ca.ancestor_concept_id = ?
      AND ca.min_levels_of_separation >= 1   -- descendants only, not the root itself
      AND c.invalid_reason IS NULL            -- active concepts only
    ORDER BY ca.min_levels_of_separation, c.concept_name
    """
    return pd.read_sql(query, con, params=(ancestor_concept_id,))

# Example usage (replace ':memory:' with path to OMOP SQLite or use your DB connection):
# con = sqlite3.connect(":memory:")   # placeholder
# df = get_omop_descendants(con, DM_T2_OMOP_CONCEPT_ID)
# print(f"OMOP descendant concepts: {len(df)}")
# print(df.head(10).to_string(index=False))

Citations

FOUNDATIONAL / METHODS
  1. [1]Cornet R, de Keizer N. Forty years of SNOMED: a literature review. BMC Medical Informatics and Decision Making. 2008;8(Suppl 1):S2.
  2. [2]Bodenreider O. The Unified Medical Language System (UMLS): integrating biomedical terminology. Nucleic Acids Research. 2004;32(Database issue):D267-D270.
APPLIED EXAMPLES
  1. [3]National Library of Medicine. SNOMED CT — Overview and access [Internet]. Bethesda (MD): NLM; [cited 2026-06-12]. Available from: https://www.nlm.nih.gov/healthit/snomedct/index.html
REPORTING & GUIDANCE
  1. [4]Voss EA, Makadia R, Matcho A, et al. Feasibility and utility of applications of the common data model to multiple, disparate observational health databases. Journal of the American Medical Informatics Association. 2015;22(3):553-564.