Trying to define 'legacy' always reminds me of US Supreme Court Justice Potter Stewart discussing the definition of obscene material:
I shall not today attempt further to define the kinds of material I understand to be embraced within that shorthand description, and perhaps I could never succeed in intelligibly doing so. But I know it when I see it
Here's my stab at a definition: Legacy code is any code whose existence hinders any work performed upon it.
We've all had that all-too-rare experience of working on excellent code. It's a joy to work with - it seems to positively invite that change that you want to implement, quietly guiding you towards the most elegant possible solution. The support framework is in place to allow you to add a test for your new code with a minimum of fuss, and the design gives you confidence that your change will not inadvertently affect the surrounding code. Working with this project reminds you why you chose to be a programmer in the first place!
Unfortunately 99% of code that I have worked with (written either by me or by someone else) doesn't have this mystical property of "excellence". Every time you want to make a change, you find that some piece of existing code gets in the way somehow. Either it's impossible to write a test, or you can write a test but you can't test your change the way you wanted to. Perhaps you find that there's already code that does something very similar to what you want to do, but it's just coupled enough to other components to make it impossible to re-use.
In other words, according to my definition above, the vast majority of code is legacy code, since it hinders you whenever you try to change it. And most of us are writing legacy code most of the time!