Using CONCEPT_ANCESTOR to generate ICD-10-CM code lists for EHR source queries — findings from three clinical domains

Hi all,

Sharing findings from a systematic evaluation we ran at Corewell Health. We’re testing whether OMOP vocabulary tables can serve as a code discovery tool for querying Epic EHR source data directly — and we want the community’s perspective on whether the gaps we found are expected limitations or structural issues that also affect standard OMOP CDM queries.

What We Were Trying to Do

Our honest broker team builds research cohorts from Epic Clarity and Caboodle. Investigators typically arrive with ICD-10 code lists derived from protocols or literature. We wanted to test whether CONCEPT_ANCESTOR could replace or augment manual ICD-10 enumeration — specifically:

  1. Anchor at a SNOMED concept (e.g., “Congenital heart disease”)
  2. Traverse CONCEPT_ANCESTOR to find all descendant SNOMED concepts
  3. Reverse-map descendants to ICD-10-CM via CONCEPT_RELATIONSHIP (‘Mapped from’)
  4. Match ICD-10 codes against Epic’s DiagnosisTerminologyDim to find patients

If this worked reliably, it would give us hierarchy-based cohort definitions that self-maintain across ICD-10-CM fiscal year updates — a significant advantage over static code lists that silently stale.

We recognize this is not the primary intended use of the vocabulary (which is standard-concept traversal within a CDM). We’re asking: is this a reasonable secondary use case, or are the gaps we found expected limitations when operating outside the standard OMOP CDM query pattern?

How We Tested It

Three clinical domains at increasing complexity. For each, we compared:

  • Hierarchy approach: CONCEPT_ANCESTOR from a SNOMED anchor → ICD-10 code expansion → patient lookup
  • Manual approach: ICD-10 codes a competent analyst would enumerate from clinical knowledge

Patient-level concordance measured on a 4.5M patient EHR.

Results

Domain 1: Parkinson’s Disease (simple)

Metric Hierarchy Manual
SNOMED descendants 12
ICD-10 codes produced 8 8
Patients found 209 209
Concordance 100%

No divergence. Both approaches find exactly the same patients. (One known mapping gap — PSP/G23.1 — is being addressed in the February release per a separate issue.)

Domain 2: Congenital Heart Disease (complex)

Anchor: 312723 (“Congenital heart disease”)

Metric Hierarchy Manual (Q20-Q24)
SNOMED descendants 928
ICD-10 codes produced 54 ~80
Patients found 108,322 129,759
Concordance
Both approaches 108,092
Hierarchy-only 230
Manual-only 21,667

The hierarchy misses 21,667 patients. Root cause: Atrial Septal Defect (4289309) and Ventricular Septal Defect (434462) are not descendants of “Congenital heart disease” (312723). They sit under “Cardiac septal defects” → “Structural disorder of heart” → “Heart disease” — a parallel branch.

The 230 hierarchy-only patients are genuine discoveries: Eisenmenger’s syndrome (I27.83), Williams syndrome (Q93.82), and neonatal CHD screening (P09.5).

Domain 3: Venous Thromboembolism (complex, dual failure)

Anchors: 444247 (“Venous thrombosis”) + 440417 (“Pulmonary embolism”)

Metric Hierarchy Manual (I26, I80-I82)
SNOMED descendants 472
ICD-10 codes produced 212 ~100
Patients found 255,343 261,764
Concordance
Both approaches 199,901
Hierarchy-only 55,442
Manual-only 61,863

VTE shows failure in both directions:

Under-capture (61,863 patients missed): The most common DVT code — I82.409 (“Acute embolism and thrombosis of unspecified deep veins of lower extremity,” 112K patients in our system) — maps to SNOMED 40481089 (“Embolism from thrombosis of vein of lower extremity”), which is NOT a descendant of “Venous thrombosis” (444247). The FY2023 peroneal vein additions (I82.451/452) map to “Disorder of vein of lower extremity” — also outside the hierarchy.

Over-capture (55,442 patients included): The hierarchy captures hemorrhoids (K64, 17.5K patients), retinal vein occlusion (H34, 10.7K patients), and obstetric venous complications (O22, 7K patients). Ontologically correct — hemorrhoids ARE venous thrombosis — but no VTE researcher would include them.

What We Learned

  1. Simple, well-coded domains (Parkinson’s): Hierarchy works perfectly. Manual and hierarchy produce identical results.
  2. Complex domains (CHD, VTE): Hierarchy is unreliable as a standalone approach. Miss rates of 17-24% on the most common codes. The hierarchy reflects SNOMED’s biological taxonomy, which doesn’t always align with how diseases are grouped for clinical research.
  3. The failure isn’t in the reverse-mapping step. The missed ICD-10 codes DO have SNOMED mappings — just to SNOMED concepts that sit outside the expected ancestor hierarchy. This suggests the same gap would affect standard OMOP CDM queries using CONCEPT_ANCESTOR (the condition_concept_id for these patients would still not be a descendant of the anchor).
  4. The hierarchy IS valuable as a discovery tool. In every domain it found clinically relevant codes that manual enumeration missed (Eisenmenger’s in CHD, obstetric VTE). The problem is completeness, not relevance.

Our Questions for the Community

  1. Is this a known limitation? Do experienced ATLAS users expect CONCEPT_ANCESTOR-based cohort definitions to have this level of incompleteness for complex domains? Is there guidance on which domains are “safe” for hierarchy-only definitions?
  2. Would these gaps also affect standard OMOP CDM queries? If a patient’s condition_occurrence record has condition_concept_id = 4289309 (ASD), a query anchored at ancestor 312723 (CHD) would miss them in the CDM too — correct?
  3. Is there a recommended multi-anchor strategy? For CHD, should we combine 312723 + 318549 (Cardiac septal defects)? Is there documentation or community guidance on selecting anchor concepts for complex domains?
  4. Is using the vocabulary for ICD-10 code discovery (our use case) reasonable, or is this an unsupported pattern? If the vocabulary team’s position is “CONCEPT_ANCESTOR is only guaranteed complete within standard-concept space, not for reverse-mapping to source vocabularies,” that’s a useful answer that sets expectations.

Our Current Approach

Based on these findings, we’ve adopted a hybrid methodology:

  • Use CONCEPT_ANCESTOR as a discovery and validation layer (finds codes you didn’t know about, flags gaps in your manual list)
  • Maintain manual ICD-10 code lists as the primary cohort definition (informed by clinical judgment)
  • Compare the two and investigate discrepancies before finalizing

This works for us operationally, but we’d like to understand whether the community considers the hierarchy gaps fixable (vocabulary improvements over time) or inherent (a characteristic of how SNOMED’s ontology maps to clinical research groupings).

Technical Details

  • Vocabulary version: v20260227 (February 2026 Athena release)
  • EHR: Epic (Caboodle data warehouse)
  • Matching path: CONCEPT_ANCESTOR → CONCEPT_RELATIONSHIP (‘Mapped from’) → ICD-10-CM concept_code → DiagnosisTerminologyDim.VALUE
  • System: 4.5M patients, Corewell Health (21-hospital system)

Happy to share the SQL or additional detail on any domain. We plan to continue testing additional domains and can report back.

Roger Carlson Corewell Health Research Institute

Hi Roger! This challenge is near and dear to my heart. This is indeed a known limitation of the vocabulary, and impacts not just the use case you describe but also standard OMOP CDM research queries.

Traditional research teams often work with ICD-based codelists, so as an analyst I’m faced with the need to translate these into OMOP concept sets. To do so I follow the exact process you’ve described; I use OMOP to discover missing codes and validate the original ICD-based list in the process of building my concept set. Doing so is incredibly time consuming and requires clinical input when discrepancies arise (which is often).

From my perspective, there are 2 separate issues/challenges. The first is OK and part of the job when we’re trying to standardize. The second is not OK and should be fixed.

  1. As you’ve pointed out, sometimes SNOMED’s method for organizing codes is just different from ICD’s or individual researchers’ methods. We can handle this by curating our concept set expression with the right mix of SNOMED codes to match the researcher’s intention.
  2. Even if we do #1 correctly we still might end up with an invalid concept set. This is due to erroneous and/or “uphill” mappings of ICD codes to SNOMED codes in the OMOP vocabulary. Errors can be reported to the vocab team and fixed. Uphill mappings, if not implemented in error, don’t currently have a solution. These occur when there is not a SNOMED code corresponding to a given ICD code, and then the ICD gets mapped to a more-general SNOMED that carries with it other ICDs and source codes that don’t match the clinical description. Currently the only way to solve these is to build a custom source concept set.

@Dymshyts led a discussion about this at last year’s Symposium, and maybe he has an update/thoughts on the path forward? :slight_smile: Vocabulathon 2025: Precise mapping

@katy-sadowski:

Spot on! The uphill mapping will drag additional conditions in. All you have to do is going through and kicking them out by hand.

But: The list will end up still better than the original ICD10 list. Seen it many times.