A developer ships a change inside a managed solution. The import runs clean, no errors, no warnings. The behaviour in the environment doesn't move an inch. Nothing about the new solution is wrong. Something sitting above it in the stack is simply winning, and the import never got a chance to matter.
That's Power Platform solution layering, and it happens at the level of each individual component, not the environment as a whole. Every table, form, and column Dataverse manages holds its own stack of layers, going all the way back to whichever solution first created it. Only the layer sitting on top of that stack decides what actually runs. A managed solution layer override is just that idea in its most common shape. Something above your import is still the one giving the orders.
How the layers stack, and which one wins
At the very top of every component's stack sits the unmanaged layer. Every unmanaged solution imported into that environment, and every ad hoc customisation someone made by hand, lands in that same single layer. There's only one per environment, regardless of how many unmanaged solutions fed into it.
Below the unmanaged layer come the managed layers. Install more than one managed solution against the same component and the most recently installed one sits above the earlier ones, free to customise whatever the earlier solution put there. Inside one managed solution's own portion of the stack, a pending upgrade named _Upgrade sits above any patches, patches stack with the newest one on top of older ones, and the base layer sits at the bottom, carrying the solution's publisher and its managed properties. Until a patch or upgrade has been applied, that base layer is what decides the component's behaviour.
At the floor of everything sits the system layer, the tables and components Dataverse needs simply to function.
Read top to bottom, the order is fixed. Unmanaged layer first, then managed layers with the newest solution highest and each one's own upgrade, patch and base stack beneath it, then the system layer underneath all of it.
The base layer is also where the publisher lives, and that matters more than it looks. Managed properties are tied to a publisher, and once they're enforced, only a solution from that same publisher can change the component going forward. The publisher also sets the prefix stamped on every custom table and column it creates. Leave a solution's publisher on the default and Dataverse hands you a random one, something like cr8a3, which is how so many environments end up with tables named after nothing.
Updating an installed solution changes this stack differently depending on which option you pick. An Upgrade, the default, rolls every patch into the base solution and deletes any component from the old version that's missing from the new one, so the end state matches the import exactly. An Update leaves those orphaned components in place and finishes faster because it skips that cleanup. Stage for Upgrade defers the deletion and installs the new version as a holding solution above the base and patch layers, tagged with an _Upgrade suffix, so old and new can run side by side while data migrates between them. Selecting Apply Solution Upgrade on the base solution later uninstalls the patches and the original base, renames the _Upgrade solution into its place, and removes whatever the original had that the new version doesn't. Either way, applying an upgrade flattens the stack into one new base layer.
In an environment where several teams have installed solutions over years, working out which one is actually sitting on top from memory doesn't hold up. If you'd rather see what's actually deployed across an environment than reconstruct it from install history, Cartographer crawls the solution metadata inside your own tenant and sends nothing outside it, and it costs nothing to run.
What creates an active layer
An active layer exists when an unmanaged customisation sits on top of a managed layer. The solution layers view flags this directly, under Layer Status. Where no unmanaged layer exists at all, the top layer is marked managed rather than active.
Most active layers exist because somebody opened a component directly in that environment and changed it there instead of shipping the change through a managed solution. Development and maker environments carry unmanaged layers by design, since everything built in them starts out unmanaged. Production and test environments aren't meant to work that way, which is why the standard guidance is to build in an unmanaged layer somewhere else and ship the result as managed, not touching the live component directly.
Active layers also appear during import itself. If a table has no fallback form specified and a managed solution brings that table in anyway, Dataverse creates an unmanaged active layer automatically for the main form, because a fallback form is required and the system gives itself one. The fix sits upstream of the import. Give the table a fallback form before exporting the unmanaged solution as managed, and there's nothing left for the system to invent.
Which components merge, and which get overridden
When two layers disagree about the same component, Dataverse resolves it one of two ways, and the type of component decides which. For everything except forms, site maps and model-driven apps, the rule is top level wins. Whatever the highest layer defines is what runs, and the layers underneath simply aren't consulted.
Forms, site maps and apps merge instead, and the mechanics differ enough to spell out.
For forms, merging only applies when the customisation touches a table that already exists in the environment. When a managed solution is packaged, its FormXML is compared against the original and only the differences travel with the solution, merging section by section. Because managed layers sit underneath the unmanaged layer, adding fields into an existing tab or section can end up sitting over whatever a managed layer already placed there. Microsoft's own recommendation is to put new elements into a new section or tab rather than an existing one, so nothing gets hidden underneath them. Where both the incoming solution and the environment already hold multiple forms for a table, the new ones get interleaved among the existing forms rather than added to the bottom. Turning on Overwrite Customizations during import doesn't change that forms still merge. Where the two sides are too far out of sync to merge cleanly, Dataverse builds an autogenerated Conflicts Tab and drops the unmergeable pieces there.
Site maps merge the same way structurally. The XML gets diffed against the original, and whatever changed, moved, was added or removed travels as the difference. New visible items land at the bottom of whichever container they belong to, not wherever you'd originally placed them, so positioning a menu item precisely means exporting the site map, editing the XML directly, and reimporting it as unmanaged. Only one site map customisation applies between publishes, so an edit that never got published is gone the moment a new definition imports over it.
Choice columns work differently again. Each new option a solution adds carries a five digit prefix built from the publisher's prefix, which keeps two publishers' options in the same choice column from colliding. When a managed solution changes a choice column's options, everything it defines becomes available in the environment, and uninstalling that solution returns the choice column to what it looked like before.
Removing an active layer
Removing an active layer is deliberate and one way, and Dataverse calls the feature Remove Active Customizations. It lives in the Solutions area of the Power Apps maker portal. Open the solution, find the component, Microsoft's own example uses the Account table, select the "..." next to it and choose "See solution layers." If the component carries an unmanaged layer, it appears labelled "Unmanaged layer" in the Solution column. Select it and click "Remove active customizations" on the command bar.
Know what you're giving up first. Removing active customisations can't be reversed, and any data tied to that unmanaged customisation can be lost with it. If the unmanaged layer is also the component's only layer, meaning there's no managed base underneath to fall back to, this option isn't available at all. The only route left is deleting the unmanaged component itself, a more serious action, and one where working out what the component is tied to matters most.
Removing the active layer doesn't delete the component. Only that layer goes, and whatever sits underneath takes over the moment it's gone.
What happens when you uninstall
Uninstalling a managed solution restores the layer beneath it. If another managed solution was installed underneath, that one now governs the component. If nothing else was there, the component falls back to whatever the system solution defines by default.
That restoration only works where something exists to restore. A form on the Account table that existed before your solution touched it has a layer underneath it going all the way down to the system layer, so uninstalling uncovers what was there before. A custom table or custom column your solution created is different, because nothing existed there before your solution added it. Custom entities and custom attributes that were part of the uninstalled solution lose their data when the solution comes out, and Microsoft documents that plainly. That loss lands specifically on the tables and columns a solution created itself, because there's no earlier layer beneath them to land on.
The opening scenario, a clean import that changes nothing, has exactly two documented causes. An unmanaged active customisation sitting on the target environment's top layer is one. Another managed solution's layer already occupying that spot is the other.
Overwrite Customizations exists to force the issue on import, but Microsoft doesn't recommend using it. It slows the import considerably, it doesn't touch components that merge, and it doesn't touch components with another managed solution already on top of them either, so it solves less than it appears to.
Block Unmanaged Customizations, a setting in the Features area of environment settings in the Power Platform admin center and off by default, does more of the actual work. Turn it on and the environment blocks importing unmanaged solutions, creating new components, and adding unmanaged changes to existing managed ones, all with an error rather than a silent active layer. Remove Active Customizations still works with the setting on, unmanaged solutions can still be created and exported, and environment variables and component enablement still change freely. Dataflows sit outside the block entirely and keep creating unmanaged layers whether the setting is on or not.
Customise in an unmanaged layer somewhere that doesn't matter, export the result as managed, and deploy only managed solutions anywhere the behaviour needs to be predictable.