Fairly minor update -- as always, let me know if there are questions or comments.

---------------------------------------------------------

Consider using abstract classes (even if there are no abstract members) if the class is designed to be a root in an inheritance hierarchy make this clear by not allowing it to be directly used.  

Annotation (Brad Abrams): In retrospect we should have made System.Exception an abstract class.    System.Exception was meant to be used as a root in the inheritance hierarchy but because we allowed it to be constructable lazy developers tend to throw it rather than using a more meaningful exception.

  Avoid prefixing or postfixing “Base”, “Root” or other such words as this type is likely to show up in public APIs.  In general base classes have simple, meaningful, pretty names because they are commonly used in public APIs.  In some cases differentiation is unavoidable because the base class is really an implementation detail and not a key design point. For example in System.Windows.Forms, the ButtonBase class is the base class for Buttons, CheckBoxes, etc.  In these cases use the XxxBase pattern. 

Do prefer using base types in public signatures rather than concrete types. This provides better opportunity for substitution and more flexibility in changing the implementation in the future.

Consider the following method:

public FileStream GetDataStream() {}

The implementation of GetDataStream is not locked into being backed by a File.  If the implementation changes to use any other type of stream (such as a NetworkStream) a breaking change will have to be made.  It would be better to use the base class Stream to gain greater flexibility.

public Stream GetDataStream() {}

 

Annotation (Brad Abrams) This guideline could be easily abused to create overly complicated designs.  If you have an API that is meant to only work with files, using a FileStream is the right thing to do.  Don’t push in abstraction unless it is called for.