Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have an Esri file geodatabase with attribute domains defined. I need to delete some of the attribute domains but can't because "The domain is used by an attribute rule.". How might I discover which feature class(es) are using the domains?

Executing: DeleteDomain R:\v5\YT_Canvec.gdb Permanency
Start Time: Thu May 19 11:01:02 2011
ERROR 999999: Error executing function.
The domain is used by an attribute rule.
Failed to execute (DeleteDomain).
Failed at Thu May 19 11:01:02 2011 (Elapsed Time: 0.00 seconds)

There are over a hundred feature classes in the geodatabase, interactively looking at the FC field properties for each one is a non-starter. The gdb is too large to convert to a personal gdb and go in the back door with ms-access (a dodgy method anyway).

(2011-May-26): Another way to phrase this is "which Feature Class is using domain X?"

share|improve this question
Are you using subtyped domains? – Kirk Kuykendall May 19 '11 at 19:43
@kirk, yes there is a subtype, but the domains I'm trying to remove are not using the subtype – matt wilkie May 19 '11 at 21:49
In that case I think Brian's code would work. – Kirk Kuykendall May 19 '11 at 21:52
@kirk, correction: I didn't think I was using subtypes+domains, but after much mucking about and opening a tech support case, it turns out I actually was using one after all. It was veritable click-fest to identify the particular remaining cuplrit. I should have invested more time in following up on your c# method! – matt wilkie May 26 '11 at 22:51

Python has methods for listing feature classes in a geodatabase, looping through each feature class in the list, listing fields in each feature class, and showing the domain of each field.

import arcpy

#Set workspace environment to geodatabase
arcpy.env.workspace = your_gdb

#Get list of feature classes in geodatabase
FCs = arcpy.ListFeatureClasses()

#Loop through feature classes in list
for FC in FCs:

    #List fields in feature class
    fields = arcpy.ListFields(FC)

    #Loop through fields
    for field in fields:

        #Check if field has domain
        if field.domain != "":

            #Print feature class, field, domain name
            print FC,, field.domain

The above code should work in ArcGIS 10 and it will print a list right in the python interpreter window. You can then copy and paste the list into a text editor or Excel to review the results more easily.

share|improve this answer
Will this handle subtyped domains too? – Kirk Kuykendall May 19 '11 at 19:43
I'm not sure if this will handle subtypes or subtyped domains. I have never used subtypes before. If there is a domain assigned to a particular field, the domain name will be printed. – Brian May 19 '11 at 20:10
beautiful, thanks Brian. Initially it didn't work for me, but eventually I remembered that listFC doesn't recurse into FeatureDatasets without some extra help (…). All good now! :) – matt wilkie May 19 '11 at 21:51
@Kirk, no it doesn't see subtypes using domains. – matt wilkie May 26 '11 at 22:48
Follow the example… to go through all subtypes and their associated domains. – Michael Miles-Stimson Jul 15 '15 at 2:11

Since I don't think python handles subtypes, I'm posting this c# code that should. I tested it with Esri's sample water/wastewater geodb and found the following unused domains:

HistoryType is not used
PLSSFirstDivisionType is not used
PLSSDirection is not used
PLSSPrincipalMeridian is not used
ParcelType is not used
PLSSSpecialSurveyType is not used
CartoLineType is not used
PLSSSecondDivisionType is not used

Often DBA's get annoyed that domains - which are essentially lookup tables - cannot be accessed via SQL.

This code tested from arcmap (updated per Matt's comment):

protected override void OnClick()
    string fgdbPath = @"C:\projects\NetTools\InfrastructureEditingTemplate\MapsandGeodatabase\LocalGovernment.gdb";
    var dict = SummarizeDomains(fgdbPath);
    // list what featureclasses use a particular domain ...
    string domName = "State_Bnd_Rules";
    if (dict.ContainsKey(domName))
        if (dict[domName].Count > 0)
            Debug.Print("{0} is used by these featureclasses: ", domName);
            foreach (string fcfldName in dict[domName])
                Debug.Print("\t{0}", fcfldName);
            Debug.Print("{0} is not used by any featureclasses", domName);
        Debug.Print("Domain name not found in geodb: {0}", domName);

private void ListDomains(Dictionary<string,List<string>> dict)
    foreach (KeyValuePair<string, List<string>> kvp in dict)
        Debug.Print("Domain {0}",kvp.Key);
        if (kvp.Value.Count > 0)
            foreach (string fcfldName in kvp.Value)
                Debug.Print("\t{0}", fcfldName);
            Debug.Print("\tUNUSED DOMAIN!");

private Dictionary<string, List<string>> SummarizeDomains(string fgdPath)
    var ws = Open(fgdPath);
    var dict = InitDict(ws);

    var enumDs1 = ws.get_Datasets(esriDatasetType.esriDTAny);
    IDataset ds;
    while ((ds = enumDs1.Next()) != null)
        Debug.Print("processing {0}", ds.Name);
        if (ds is IObjectClass)
            LoadDomains((IObjectClass)ds, dict);
        else if (ds is IFeatureDataset)
            var enumDs2 = ds.Subsets;
            IDataset ds2;
            while ((ds2 = enumDs2.Next()) != null)
                if (ds2 is IObjectClass)
                    LoadDomains((IObjectClass)ds2, dict);
    return dict;
private void LoadDomains(IObjectClass oc, Dictionary<string, List<string>> dict)
    if (oc is ISubtypes && ((ISubtypes)oc).HasSubtype)
        LoadSubtypeDomains(oc, dict);
        for (int i = 0; i < oc.Fields.FieldCount; i++)
            var fld = oc.Fields.get_Field(i);
            if (fld.Domain == null)
            if (dict.ContainsKey(fld.Domain.Name))
                throw new Exception("domain not found: " + fld.Domain.Name);
private void LoadSubtypeDomains(IObjectClass oc, Dictionary<string, List<string>> dict)
    ISubtypes subTypes = oc as ISubtypes;
    var enumSubtypes = subTypes.Subtypes;
    int code;
    string stName;
    while ((stName = enumSubtypes.Next(out code)) != null)
        for (int i = 0; i < oc.Fields.FieldCount; i++)
            string fldName = oc.Fields.get_Field(i).Name;
            var domain = subTypes.get_Domain(code, fldName);
            if (domain != null)
                if (dict.ContainsKey(domain.Name))
                    throw new Exception("domain not found: " + domain.Name);
private Dictionary<string, List<string>> InitDict(IWorkspace ws)
    var dict = new Dictionary<string, List<string>>(StringComparer.InvariantCultureIgnoreCase);
    var enumDomain = ((IWorkspaceDomains)ws).Domains;
    IDomain d = null;
    while ((d = enumDomain.Next()) != null)
        dict.Add(d.Name, new List<string>());
    return dict;

private IWorkspace Open(string fgdbPath)
    Type t = Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory");
    var wsf = Activator.CreateInstance(t) as IWorkspaceFactory;
    return wsf.OpenFromFile(fgdbPath, 0);
share|improve this answer
while listing unused domains is useful, this is the inverse of the problem to be solved. I was actually looking for "which FC is using domain X?" (so I may remove the link, and make the domain an unused domain). ((I still haven't tried the code, I'm just going on the name of the function)) – matt wilkie May 26 '11 at 22:55
@matt oh, yeah, that make sense. I've changed the code to show how to do that. – Kirk Kuykendall May 27 '11 at 13:52
uhh, maybe this should be a full fledged question, but, where do I put this code? I can't locate the v10 equivalent of the VBA editor (Tools->Macros->Visual Basic Editor). – matt wilkie May 31 '11 at 20:51
You'll need to install Visual Studio Express (free) or greater, and the ArcGIS SDK. Once you've done that, you should be able to follow this walkthrough for creating a command button, then copy and paste my code into the Click event. You'll also need to add appropriate references to the project. – Kirk Kuykendall May 31 '11 at 21:26
up vote 4 down vote accepted

Unfortunately Brian's answer, which is a direct and usable answer the question asked, does not solve my actual problem. I presume because of a bug in the gdb at hand (even though none of the feature classes have domains attached, there is still one I'm not allowed to delete). In any case I found another method for determining which fc's have associated domains. It's interactive, but much faster than going through each field property on every single fc:

Drag and drop bunches of fc's from problem gdb to another gdb and inspect the Data Transfer dialog. Linked attribute domains, if any, will be at the bottom of the list. Repeat in smaller and smaller bunches until you narrow down which @$%## fc is giving you a hard time.

finally narrowed down to 2 FCs linked to a CV domain

share|improve this answer
Curiously, even though drag-n-drop says HD_148009_2 is linked to the CV Domain Permanency, Brian's arcpy script reports no linked domain, and neither does the Feature Class Properties fields inspector in ArcCatalog. However now I've finally narrowed it down enough to log a bug report with Esri tech support. – matt wilkie May 19 '11 at 22:59

This is what I imagine Matt Wilkie had to look up and write to augment Brian's code. I had to get all domains for tables, feature classes in the root directory of a database, and features in all feature datasets. I exported the information as a csv to allow some other workers to clean up our geodatabase environments of old domains.

def domainInfo(csvExportFolder):
    import arcpy,csv,os

    fcTabList = []
    list = []

    #Set workspace environment to geodatabase
    arcpy.env.workspace = r"H:\GIS\SDEConnections\Admin\Infrastructure.sde"

    #Prepping the csv
    csvFile = csv.writer(open(csvExportFolder+"\\"+ "Infrastructure Domains" + ".csv","wb"),delimiter = "|")

    #Get list of all features in geodatabase
    fdsList = arcpy.ListDatasets()
    fcs = arcpy.ListFeatureClasses()
    tbs = arcpy.ListTables()

    for fds in fdsList:
        fcs = arcpy.ListFeatureClasses("","",fds)
        if len(fcs) != 0:
            for fc in fcs:

    for fc in fcs:

    for tb in tbs:

    # Loop through all features in the database list
    for item in fcTabList:
        fds = item[0]
        fc = item[1]
        # List fields in feature class
        fields = arcpy.ListFields(fc)

        # Loop through fields
        for field in fields:

            # Check if field has domain
            if field.domain != "":

                # Print feature class, field, domain name

def main():
    csvExportFolder = r"H:\GIS"

if __name__ == "__main__":
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.